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")