From 737afcb34376dea9bee8bb1dc73536a0197be5f2 Mon Sep 17 00:00:00 2001 From: Anton Lakotka Date: Mon, 6 Feb 2023 10:22:36 +0100 Subject: [PATCH] [Gradle] Move creation of GranularMetadataTransformation to source set Now it is encapsulated to DefaultKotlinSourceSet and is lazily created upon demand during project import But metadata configurations still should be created during metadata target configuration. ^KT-56431 Verification Pending --- .../mpp/resolvableMetadataConfiguration.kt | 20 +++- .../plugin/sources/DefaultKotlinSourceSet.kt | 83 +++++++++++++++- .../KotlinMetadataTargetConfigurator.kt | 97 ++++--------------- ...ropMetadataDependencyTransformationTask.kt | 5 +- 4 files changed, 119 insertions(+), 86 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/resolvableMetadataConfiguration.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/resolvableMetadataConfiguration.kt index 4b47696a8a5..ed4af8d8bd9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/resolvableMetadataConfiguration.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/resolvableMetadataConfiguration.kt @@ -7,14 +7,20 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project import org.gradle.api.artifacts.Configuration +import org.gradle.api.attributes.Category +import org.gradle.api.attributes.Usage import org.gradle.api.provider.Provider +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.categoryByName import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes import org.jetbrains.kotlin.gradle.utils.markResolvable import org.jetbrains.kotlin.gradle.plugin.sources.InternalKotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX import org.jetbrains.kotlin.gradle.plugin.sources.disambiguateName import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations -import org.jetbrains.kotlin.gradle.targets.metadata.ALL_COMPILE_METADATA_CONFIGURATION_NAME +import org.jetbrains.kotlin.gradle.plugin.usageByName +import org.jetbrains.kotlin.gradle.plugin.usesPlatformOf +import org.jetbrains.kotlin.gradle.utils.getOrCreate import org.jetbrains.kotlin.gradle.utils.listProperty import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.tooling.core.extrasLazyProperty @@ -56,7 +62,7 @@ internal val InternalKotlinSourceSet.resolvableMetadataConfiguration: Configurat } }) - val allCompileMetadataConfiguration = project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME) + val allCompileMetadataConfiguration = project.allCompileMetadataConfiguration /* Ensure consistent dependency resolution result within the whole module */ configuration.shouldResolveConsistentlyWith(allCompileMetadataConfiguration) @@ -65,6 +71,16 @@ internal val InternalKotlinSourceSet.resolvableMetadataConfiguration: Configurat configuration } +internal val Project.allCompileMetadataConfiguration get(): Configuration = + configurations.getOrCreate("allSourceSetsCompileDependenciesMetadata", invokeWhenCreated = { + it.markResolvable() + + val metadataTarget = multiplatformExtension.metadata() + it.usesPlatformOf(metadataTarget) + it.attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA)) + it.attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY)) + }) + private inline fun Project.listProvider(noinline provider: () -> List): Provider> { return project.objects.listProperty().apply { set(project.provider(provider)) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt index 89f68361787..48f58dc9f91 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt @@ -9,13 +9,16 @@ package org.jetbrains.kotlin.gradle.plugin.sources import org.gradle.api.Action import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration import org.gradle.api.file.SourceDirectorySet import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.mpp.* +import org.jetbrains.kotlin.gradle.targets.metadata.dependsOnClosureWithInterCompilationDependencies import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.tooling.core.MutableExtras import org.jetbrains.kotlin.tooling.core.closure @@ -125,7 +128,9 @@ abstract class DefaultKotlinSourceSet @Inject constructor( * Returns [GranularMetadataTransformation] for all requested compile dependencies * scopes: API, IMPLEMENTATION, COMPILE_ONLY; See [KotlinDependencyScope.compileScopes] */ - internal var compileDependenciesTransformation: GranularMetadataTransformation? = null + internal val compileDependenciesTransformation: GranularMetadataTransformation? by lazy { + createAndConfigureDependencyTransformationForSourceSet() + } private val _requiresVisibilityOf = mutableSetOf() @@ -226,7 +231,75 @@ fun KotlinMultiplatformExtension.findSourceSetsDependingOn(sourceSet: KotlinSour return sourceSet.closure { seedSourceSet -> sourceSets.filter { otherSourceSet -> seedSourceSet in otherSourceSet.dependsOn } } } -internal val DefaultKotlinSourceSet.compileDependenciesTransformationOrFail: GranularMetadataTransformation - get() = compileDependenciesTransformation - ?: error("Accessing Compile Dependencies Transformations that is not yet initialised; " + - "Check when compileDependenciesTransformation is set") \ No newline at end of file +private fun DefaultKotlinSourceSet.createAndConfigureDependencyTransformationForSourceSet(): GranularMetadataTransformation? { + // Create only for source sets in multiplatform plugin + project.multiplatformExtensionOrNull ?: return null + + val parentSourceSetVisibilityProvider = ParentSourceSetVisibilityProvider { componentIdentifier -> + dependsOnClosureWithInterCompilationDependencies(this).filterIsInstance() + .mapNotNull { it.compileDependenciesTransformation } + .flatMap { it.visibleSourceSetsByComponentId[componentIdentifier].orEmpty() } + .toSet() + } + + val granularMetadataTransformation = GranularMetadataTransformation( + params = GranularMetadataTransformation.Params(project, this), + parentSourceSetVisibilityProvider = parentSourceSetVisibilityProvider + ) + + /** + * + * This method is only intended to be called on deprecated DependenciesMetadata configurations to ensure + * correct behaviour in import. + * + * KGP based dependency resolution is therefore unaffected. + * + * Ensure that the [configuration] excludes the dependencies that are classified by this [GranularMetadataTransformation] as + * [MetadataDependencyResolution.Exclude], and uses exactly the same versions as were resolved for the requested + * dependencies during the transformation. + */ + fun applyTransformationToLegacyDependenciesMetadataConfiguration( + configuration: Configuration, + transformation: GranularMetadataTransformation + ) { + // Run this action immediately before the configuration first takes part in dependency resolution: + configuration.withDependencies { + val (unrequested, requested) = transformation.metadataDependencyResolutions + .partition { it is MetadataDependencyResolution.Exclude } + + unrequested.forEach { + val (group, name) = it.projectDependency(project)?.run { + /** Note: the project dependency notation here should be exactly this, group:name, + * not from [ModuleIds.fromProjectPathDependency], as `exclude` checks it against the project's group:name */ + ModuleDependencyIdentifier(group.toString(), name) + } ?: ModuleIds.fromComponent(project, it.dependency) + configuration.exclude(mapOf("group" to group, "module" to name)) + } + + requested.filter { it.dependency.currentBuildProjectIdOrNull == null }.forEach { + val (group, name) = ModuleIds.fromComponent(project, it.dependency) + val notation = listOfNotNull(group.orEmpty(), name, it.dependency.moduleVersion?.version).joinToString(":") + configuration.resolutionStrategy.force(notation) + } + } + } + + @Suppress("DEPRECATION") + /* + Older IDEs still rely on resolving the metadata configurations explicitly. + Dependencies will be coming from extending the newer 'resolvableMetadataConfiguration'. + + the intransitiveMetadataConfigurationName will not extend this mechanism, since it only + relies on dependencies being added explicitly by the Kotlin Gradle Plugin + */ + listOf( + apiMetadataConfigurationName, + implementationMetadataConfigurationName, + compileOnlyMetadataConfigurationName + ).forEach { configurationName -> + val configuration = project.configurations.getByName(configurationName) + applyTransformationToLegacyDependenciesMetadataConfiguration(configuration, granularMetadataTransformation) + } + + return granularMetadataTransformation +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index f1d093dd735..fc6233c6f29 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -6,8 +6,6 @@ package org.jetbrains.kotlin.gradle.targets.metadata import org.gradle.api.Project -import org.gradle.api.Task -import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.result.ResolvedArtifactResult import org.gradle.api.attributes.Category import org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE @@ -21,8 +19,6 @@ import org.gradle.api.tasks.bundling.Zip import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.plugin.* -import org.jetbrains.kotlin.gradle.plugin.ide.Idea222Api -import org.jetbrains.kotlin.gradle.plugin.ide.ideaImportDependsOn import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.* import org.jetbrains.kotlin.gradle.plugin.sources.* @@ -92,7 +88,7 @@ class KotlinMetadataTargetConfigurator : configureProjectStructureMetadataGeneration(target.project, allMetadataJar) - setupDependencyTransformationForCommonSourceSets(target) + configureMetadataDependenciesConfigurationsForCommonSourceSets(target) target.project.configurations.getByName(target.apiElementsConfigurationName).run { attributes.attribute(USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA)) @@ -166,10 +162,12 @@ class KotlinMetadataTargetConfigurator : return result } - private fun setupDependencyTransformationForCommonSourceSets(target: KotlinMetadataTarget) { + private fun configureMetadataDependenciesConfigurationsForCommonSourceSets(target: KotlinMetadataTarget) { target.project.whenEvaluated { kotlinExtension.sourceSets.all { - setupDependencyTransformationForSourceSet(target.project, it) + if (it is DefaultKotlinSourceSet) { + configureMetadataDependenciesConfigurations(target.project, it) + } } } } @@ -368,79 +366,26 @@ class KotlinMetadataTargetConfigurator : } } - private fun setupDependencyTransformationForSourceSet( + private fun configureMetadataDependenciesConfigurations( project: Project, - sourceSet: KotlinSourceSet + sourceSet: DefaultKotlinSourceSet ) { - val parentSourceSetVisibilityProvider = ParentSourceSetVisibilityProvider { componentIdentifier -> - dependsOnClosureWithInterCompilationDependencies(sourceSet).filterIsInstance() - .flatMap { it.compileDependenciesTransformationOrFail.visibleSourceSetsByComponentId[componentIdentifier].orEmpty() } - .toSet() - } - - val granularMetadataTransformation = GranularMetadataTransformation( - params = GranularMetadataTransformation.Params(project, sourceSet), - parentSourceSetVisibilityProvider = parentSourceSetVisibilityProvider - ) + /* + Older IDEs still rely on resolving the metadata configurations explicitly. + Dependencies will be coming from extending the newer 'resolvableMetadataConfiguration'. + the intransitiveMetadataConfigurationName will not extend this mechanism, since it only + relies on dependencies being added explicitly by the Kotlin Gradle Plugin + */ @Suppress("DEPRECATION") - if (sourceSet is DefaultKotlinSourceSet) { - sourceSet.compileDependenciesTransformation = granularMetadataTransformation - - /* - Older IDEs still rely on resolving the metadata configurations explicitly. - Dependencies will be coming from extending the newer 'resolvableMetadataConfiguration'. - - the intransitiveMetadataConfigurationName will not extend this mechanism, since it only - relies on dependencies being added explicitly by the Kotlin Gradle Plugin - */ - listOf( - sourceSet.apiMetadataConfigurationName, - sourceSet.implementationMetadataConfigurationName, - sourceSet.compileOnlyMetadataConfigurationName - ).forEach { configurationName -> - val configuration = project.configurations.getByName(configurationName) - configuration.extendsFrom(sourceSet.resolvableMetadataConfiguration) - configuration.shouldResolveConsistentlyWith(sourceSet.resolvableMetadataConfiguration) - project.applyTransformationToLegacyDependenciesMetadataConfiguration(configuration, granularMetadataTransformation) - } - } - } - - /** - * - * This method is only intended to be called on deprecated DependenciesMetadata configurations to ensure - * correct behaviour in import. - * - * KGP based dependency resolution is therefore unaffected. - * - * Ensure that the [configuration] excludes the dependencies that are classified by this [GranularMetadataTransformation] as - * [MetadataDependencyResolution.Exclude], and uses exactly the same versions as were resolved for the requested - * dependencies during the transformation. - */ - private fun Project.applyTransformationToLegacyDependenciesMetadataConfiguration( - configuration: Configuration, - transformation: GranularMetadataTransformation - ) { - // Run this action immediately before the configuration first takes part in dependency resolution: - configuration.withDependencies { - val (unrequested, requested) = transformation.metadataDependencyResolutions - .partition { it is MetadataDependencyResolution.Exclude } - - unrequested.forEach { - val (group, name) = it.projectDependency(this)?.run { - /** Note: the project dependency notation here should be exactly this, group:name, - * not from [ModuleIds.fromProjectPathDependency], as `exclude` checks it against the project's group:name */ - ModuleDependencyIdentifier(group.toString(), name) - } ?: ModuleIds.fromComponent(project, it.dependency) - configuration.exclude(mapOf("group" to group, "module" to name)) - } - - requested.filter { it.dependency.currentBuildProjectIdOrNull == null }.forEach { - val (group, name) = ModuleIds.fromComponent(project, it.dependency) - val notation = listOfNotNull(group.orEmpty(), name, it.dependency.moduleVersion?.version).joinToString(":") - configuration.resolutionStrategy.force(notation) - } + listOf( + sourceSet.apiMetadataConfigurationName, + sourceSet.implementationMetadataConfigurationName, + sourceSet.compileOnlyMetadataConfigurationName + ).forEach { configurationName -> + val configuration = project.configurations.getByName(configurationName) + configuration.extendsFrom(sourceSet.resolvableMetadataConfiguration) + configuration.shouldResolveConsistentlyWith(sourceSet.resolvableMetadataConfiguration) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyTransformationTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyTransformationTask.kt index 73d2f54f81e..0021b896fac 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyTransformationTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyTransformationTask.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.Choos import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets.MetadataProvider.ProjectMetadataProvider import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.toKpmModuleIdentifiers import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet -import org.jetbrains.kotlin.gradle.plugin.sources.compileDependenciesTransformationOrFail import org.jetbrains.kotlin.gradle.plugin.sources.internal import org.jetbrains.kotlin.gradle.tasks.dependsOn import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask @@ -156,8 +155,8 @@ internal open class CInteropMetadataDependencyTransformationTask @Inject constru @get:Internal protected val chooseVisibleSourceSets get() = sourceSet - .compileDependenciesTransformationOrFail - .metadataDependencyResolutions + .compileDependenciesTransformation + .metadataDependencyResolutionsOrEmpty .resolutionsToTransform() @Suppress("unused")