[Gradle] Implement IdeMultiplatformImport using new IdeaKotlinClasspath

^KT-55492 Verification Pending
This commit is contained in:
Sebastian Sellmair
2022-12-15 15:13:12 +01:00
committed by Space Team
parent 53c5444a7a
commit e32cff3b38
24 changed files with 273 additions and 214 deletions
@@ -7,7 +7,10 @@ package org.jetbrains.kotlin.gradle.idea.proto.tcs
import org.jetbrains.kotlin.gradle.idea.proto.classLoaderForBackwardsCompatibleClasses import org.jetbrains.kotlin.gradle.idea.proto.classLoaderForBackwardsCompatibleClasses
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationLogger import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinSerializationLogger
import org.jetbrains.kotlin.gradle.idea.tcs.* import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinProjectArtifactDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinSourceDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinUnresolvedBinaryDependency
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.TestIdeaKotlinDependencySerializer import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.TestIdeaKotlinDependencySerializer
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.TestIdeaKotlinInstances import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.TestIdeaKotlinInstances
import org.jetbrains.kotlin.gradle.idea.testFixtures.utils.copy import org.jetbrains.kotlin.gradle.idea.testFixtures.utils.copy
@@ -66,27 +69,6 @@ class IdeaKotlinDependencyBackwardsCompatibilityTest {
assertEquals(dependency.coordinates, deserializedCopied.coordinates) assertEquals(dependency.coordinates, deserializedCopied.coordinates)
assertEquals(dependency.extras, deserializedCopied.extras) assertEquals(dependency.extras, deserializedCopied.extras)
} }
@Test
fun `test - empty classpath`() {
val classpath = TestIdeaKotlinInstances.emptyClasspath
val binary = TestIdeaKotlinDependencySerializer().serialize(classpath)
val deserialized = deserializeIdeaKotlinDependencyWithBackwardsCompatibleClasses(binary)
val copied = deserialized.copy<IdeaKotlinClasspath>()
assertEquals(classpath.toSet(), copied.toSet())
}
@Test
fun `test - simple classpath`() {
val classpath = TestIdeaKotlinInstances.simpleClasspath
val binary = TestIdeaKotlinDependencySerializer().serialize(classpath)
val deserialized = deserializeIdeaKotlinDependencyWithBackwardsCompatibleClasses(binary)
val copied = deserialized.copy<IdeaKotlinClasspath>()
assertEquals(classpath.toSet(), copied.toSet())
}
} }
private fun deserializeIdeaKotlinDependencyWithBackwardsCompatibleClasses(project: ByteArray): Any { private fun deserializeIdeaKotlinDependencyWithBackwardsCompatibleClasses(project: ByteArray): Any {
@@ -335,6 +335,7 @@ public final class org/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinClasspath : ja
public fun add (Ljava/io/File;)Z public fun add (Ljava/io/File;)Z
public synthetic fun add (Ljava/lang/Object;)Z public synthetic fun add (Ljava/lang/Object;)Z
public fun addAll (Ljava/util/Collection;)Z public fun addAll (Ljava/util/Collection;)Z
public final fun addAll (Lorg/jetbrains/kotlin/gradle/idea/tcs/IdeaKotlinClasspath;)Z
public fun clear ()V public fun clear ()V
public fun contains (Ljava/io/File;)Z public fun contains (Ljava/io/File;)Z
public final fun contains (Ljava/lang/Object;)Z public final fun contains (Ljava/lang/Object;)Z
@@ -23,6 +23,10 @@ class IdeaKotlinClasspath private constructor(private val files: MutableSet<File
return files.add(normalise(element)) return files.add(normalise(element))
} }
fun addAll(classpath: IdeaKotlinClasspath): Boolean {
return files.addAll(classpath.files)
}
override fun addAll(elements: Collection<File>): Boolean { override fun addAll(elements: Collection<File>): Boolean {
return files.addAll(elements.map(::normalise)) return files.addAll(elements.map(::normalise))
} }
@@ -25,7 +25,6 @@ data class IdeaKotlinBinaryCoordinates(
} }
} }
@IdeaKotlinModel
data class IdeaKotlinProjectCoordinates( data class IdeaKotlinProjectCoordinates(
val buildId: String, val buildId: String,
val projectPath: String, val projectPath: String,
@@ -8,8 +8,8 @@ package org.jetbrains.kotlin.gradle
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.commonizer.CommonizerTarget import org.jetbrains.kotlin.commonizer.CommonizerTarget
import org.jetbrains.kotlin.commonizer.identityString import org.jetbrains.kotlin.commonizer.identityString
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency.Companion.CLASSPATH_BINARY_TYPE
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.extras.isCommonized import org.jetbrains.kotlin.gradle.idea.tcs.extras.isCommonized
import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeDistribution import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeDistribution
@@ -37,7 +37,7 @@ class MppIdeDependencyResolutionIT : KGPBaseTest() {
filterIsInstance<IdeaKotlinResolvedBinaryDependency>() filterIsInstance<IdeaKotlinResolvedBinaryDependency>()
.filter { !it.isNativeStdlib } .filter { !it.isNativeStdlib }
.filter { it.isNativeDistribution } .filter { it.isNativeDistribution }
.filter { it.binaryType == CLASSPATH_BINARY_TYPE } .filter { it.binaryType == IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE }
val nativeMainDependencies = dependencies["nativeMain"].filterNativePlatformDependencies() val nativeMainDependencies = dependencies["nativeMain"].filterNativePlatformDependencies()
val nativeTestDependencies = dependencies["nativeTest"].filterNativePlatformDependencies() val nativeTestDependencies = dependencies["nativeTest"].filterNativePlatformDependencies()
@@ -10,9 +10,7 @@ import org.gradle.api.Project
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
import org.jetbrains.kotlin.gradle.android.AndroidKotlinSourceSet.Companion.android import org.jetbrains.kotlin.gradle.android.AndroidKotlinSourceSet.Companion.android
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates import org.jetbrains.kotlin.gradle.idea.tcs.*
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.tooling.core.mutableExtrasOf import org.jetbrains.kotlin.tooling.core.mutableExtrasOf
@@ -25,13 +23,13 @@ internal fun Project.androidBootClasspath(): FileCollection {
internal class AndroidBootClasspathIdeDependencyResolver(private val project: Project) : IdeDependencyResolver { internal class AndroidBootClasspathIdeDependencyResolver(private val project: Project) : IdeDependencyResolver {
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> { override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> {
if (sourceSet.android == null) return emptySet() if (sourceSet.android == null) return emptySet()
return project.androidBootClasspath().files.map { file -> return setOf(
IdeaKotlinResolvedBinaryDependency( IdeaKotlinResolvedBinaryDependency(
binaryType = IdeaKotlinDependency.CLASSPATH_BINARY_TYPE, binaryType = IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE,
binaryFile = file, classpath = IdeaKotlinClasspath(project.androidBootClasspath().files),
extras = mutableExtrasOf(), extras = mutableExtrasOf(),
coordinates = IdeaKotlinBinaryCoordinates("com.android", "sdk", "7.4") coordinates = IdeaKotlinBinaryCoordinates("com.android", "sdk", "7.4")
) )
}.toSet() )
} }
} }
@@ -0,0 +1,70 @@
/*
* 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.ide
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.extras.documentationClasspath
import org.jetbrains.kotlin.gradle.idea.tcs.extras.sourcesClasspath
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver.Companion.DOCUMENTATION_BINARY_TYPE
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver.Companion.SOURCES_BINARY_TYPE
fun interface IdeAdditionalArtifactResolver {
fun resolve(sourceSet: KotlinSourceSet, dependencies: Set<IdeaKotlinDependency>)
}
internal fun IdeDependencyResolver.withAdditionalArtifactResolver(resolver: IdeAdditionalArtifactResolver) =
IdeDependencyResolver { sourceSet ->
this@withAdditionalArtifactResolver.resolve(sourceSet).also { result ->
resolver.resolve(sourceSet, result)
}
}
internal fun IdeAdditionalArtifactResolver(resolvers: Iterable<IdeAdditionalArtifactResolver?>) =
IdeAdditionalArtifactResolver { sourceSet, dependencies ->
resolvers.forEach { resolver -> resolver?.resolve(sourceSet, dependencies) }
}
/**
* Creates an [IdeAdditionalArtifactResolver] from a given [IdeDependencyResolver]:
* Dependencies from the [IdeDependencyResolver] need to resolve sources and javadoc using
* the [SOURCES_BINARY_TYPE] or [DOCUMENTATION_BINARY_TYPE]
*/
fun IdeAdditionalArtifactResolver(resolver: IdeDependencyResolver) = IdeAdditionalArtifactResolver { sourceSet, dependencies ->
/*
Group already resolved dependencies by their coordinates (ignoring sourceSetName, since -sources.jar are not published
on a "per source set" level.)
*/
val dependenciesByCoordinates = dependencies.filterIsInstance<IdeaKotlinResolvedBinaryDependency>()
.filter { it.binaryType == IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE }
.groupBy { it.coordinates?.copy(sourceSetName = null) }
/*
Use the passed resolver to resolve the -sources.jar and -javadoc jar dependencies as idea dependencies.
For each dependency, we will find the dependencies to add this artifacts by matching the coordinates.
*/
resolver.resolve(sourceSet).filterIsInstance<IdeaKotlinResolvedBinaryDependency>()
.filter { it.binaryType == SOURCES_BINARY_TYPE || it.binaryType == DOCUMENTATION_BINARY_TYPE }
.forEach forEachSourceOrDocumentationDependency@{ sourceOrDocumentationDependency ->
/* Find dependencies that match by coordinates and add the artifacts */
dependenciesByCoordinates[sourceOrDocumentationDependency.coordinates ?: return@forEachSourceOrDocumentationDependency]
.orEmpty().forEach forEachMatchedDependency@{ dependency ->
val classpath = when (sourceOrDocumentationDependency.binaryType) {
SOURCES_BINARY_TYPE -> dependency.sourcesClasspath
DOCUMENTATION_BINARY_TYPE -> dependency.documentationClasspath
else -> return@forEachMatchedDependency
}
classpath.addAll(dependency.classpath)
}
}
}
fun IdeDependencyResolver.asAdditionalArtifactResolver() = IdeAdditionalArtifactResolver(this)
@@ -26,6 +26,9 @@ fun interface IdeDependencyResolver {
} }
companion object { companion object {
const val SOURCES_BINARY_TYPE = "SOURCES"
const val DOCUMENTATION_BINARY_TYPE = "DOCUMENTATION"
var IdeaKotlinDependency.resolvedBy: IdeDependencyResolver? by extrasReadWriteProperty("resolvedBy") var IdeaKotlinDependency.resolvedBy: IdeDependencyResolver? by extrasReadWriteProperty("resolvedBy")
var IdeaKotlinDependency.gradleArtifact: ResolvedArtifactResult? by extrasReadWriteProperty("gradleArtifact") var IdeaKotlinDependency.gradleArtifact: ResolvedArtifactResult? by extrasReadWriteProperty("gradleArtifact")
} }
@@ -15,9 +15,7 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtension import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtension
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtensionBuilder import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtensionBuilder
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.androidJvm import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.*
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.common
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.extraProperties import org.jetbrains.kotlin.gradle.plugin.extraProperties
import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.DependencyResolutionLevel.Default import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.DependencyResolutionLevel.Default
@@ -50,6 +48,14 @@ interface IdeMultiplatformImport {
level: DependencyResolutionLevel = Default, level: DependencyResolutionLevel = Default,
) )
@ExternalKotlinTargetApi
fun registerAdditionalArtifactResolver(
resolver: IdeAdditionalArtifactResolver,
constraint: SourceSetConstraint,
phase: AdditionalArtifactResolutionPhase,
level: AdditionalArtifactResolutionLevel = AdditionalArtifactResolutionLevel.Default
)
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
fun registerDependencyTransformer( fun registerDependencyTransformer(
transformer: IdeDependencyTransformer, transformer: IdeDependencyTransformer,
@@ -112,6 +118,16 @@ interface IdeMultiplatformImport {
Default, Overwrite Default, Overwrite
} }
enum class AdditionalArtifactResolutionPhase {
PreAdditionalArtifactResolution,
SourcesAndJavadocArtifactResolution,
PostAdditionalArtifactResolution
}
enum class AdditionalArtifactResolutionLevel {
Default, Overwrite
}
/** /**
* Any [IdeDependencyResolver] has to be registered for a given transformation phase. * Any [IdeDependencyResolver] has to be registered for a given transformation phase.
* The phases will be executed in the order of this enums ordinal. * The phases will be executed in the order of this enums ordinal.
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPro
import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.SourceSetConstraint import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.SourceSetConstraint
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.* import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.*
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyTransformers.IdePlatformStdlibCommonDependencyFilter import org.jetbrains.kotlin.gradle.plugin.ide.dependencyTransformers.IdePlatformStdlibCommonDependencyFilter
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyTransformers.UnusedSourcesAndDocumentationFilter
internal fun IdeMultiplatformImport(extension: KotlinProjectExtension): IdeMultiplatformImport { internal fun IdeMultiplatformImport(extension: KotlinProjectExtension): IdeMultiplatformImport {
return IdeMultiplatformImportImpl(extension).apply { return IdeMultiplatformImportImpl(extension).apply {
@@ -96,13 +95,6 @@ internal fun IdeMultiplatformImport(extension: KotlinProjectExtension): IdeMulti
level = IdeMultiplatformImport.DependencyResolutionLevel.Default level = IdeMultiplatformImport.DependencyResolutionLevel.Default
) )
registerDependencyResolver(
resolver = IdeNativeStdlibSourcesResolver,
constraint = SourceSetConstraint.isNative,
phase = IdeMultiplatformImport.DependencyResolutionPhase.SourcesAndDocumentationResolution,
level = IdeMultiplatformImport.DependencyResolutionLevel.Default
)
registerDependencyResolver( registerDependencyResolver(
resolver = IdePlatformSourcesResolver(), resolver = IdePlatformSourcesResolver(),
constraint = SourceSetConstraint.isSinglePlatformType, constraint = SourceSetConstraint.isSinglePlatformType,
@@ -110,19 +102,19 @@ internal fun IdeMultiplatformImport(extension: KotlinProjectExtension): IdeMulti
level = IdeMultiplatformImport.DependencyResolutionLevel.Default level = IdeMultiplatformImport.DependencyResolutionLevel.Default
) )
registerDependencyResolver( registerAdditionalArtifactResolver(
resolver = IdeMetadataSourcesResolver(), resolver = IdeMetadataSourcesResolver(),
constraint = !SourceSetConstraint.isSinglePlatformType, constraint = !SourceSetConstraint.isSinglePlatformType,
phase = IdeMultiplatformImport.DependencyResolutionPhase.SourcesAndDocumentationResolution, phase = IdeMultiplatformImport.AdditionalArtifactResolutionPhase.SourcesAndJavadocArtifactResolution,
level = IdeMultiplatformImport.DependencyResolutionLevel.Default level = IdeMultiplatformImport.AdditionalArtifactResolutionLevel.Default
) )
if (extension.project.kotlinPropertiesProvider.enableSlowIdeSourcesJarResolver) { if (extension.project.kotlinPropertiesProvider.enableSlowIdeSourcesJarResolver) {
registerDependencyResolver( registerAdditionalArtifactResolver(
resolver = IdeArtifactResolutionQuerySourcesAndDocumentationResolver, resolver = IdeArtifactResolutionQuerySourcesAndDocumentationResolver,
constraint = SourceSetConstraint.unconstrained, constraint = SourceSetConstraint.unconstrained,
phase = IdeMultiplatformImport.DependencyResolutionPhase.SourcesAndDocumentationResolution, phase = IdeMultiplatformImport.AdditionalArtifactResolutionPhase.SourcesAndJavadocArtifactResolution,
level = IdeMultiplatformImport.DependencyResolutionLevel.Default level = IdeMultiplatformImport.AdditionalArtifactResolutionLevel.Default
) )
} }
@@ -132,12 +124,6 @@ internal fun IdeMultiplatformImport(extension: KotlinProjectExtension): IdeMulti
phase = IdeMultiplatformImport.DependencyTransformationPhase.DependencyFilteringPhase, phase = IdeMultiplatformImport.DependencyTransformationPhase.DependencyFilteringPhase,
) )
registerDependencyTransformer(
transformer = UnusedSourcesAndDocumentationFilter,
constraint = SourceSetConstraint.unconstrained,
phase = IdeMultiplatformImport.DependencyTransformationPhase.DependencyFilteringPhase
)
registerDependencyEffect( registerDependencyEffect(
effect = IdeDependencyLogger, effect = IdeDependencyLogger,
constraint = SourceSetConstraint.unconstrained constraint = SourceSetConstraint.unconstrained
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.*
import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.Companion.logger import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.Companion.logger
import org.jetbrains.kotlin.tooling.core.Extras import org.jetbrains.kotlin.tooling.core.Extras
import org.jetbrains.kotlin.utils.addToStdlib.measureTimeMillisWithResult import org.jetbrains.kotlin.utils.addToStdlib.measureTimeMillisWithResult
import kotlin.system.measureTimeMillis
internal class IdeMultiplatformImportImpl( internal class IdeMultiplatformImportImpl(
@@ -47,6 +48,7 @@ internal class IdeMultiplatformImportImpl(
} }
private val registeredDependencyResolvers = mutableListOf<RegisteredDependencyResolver>() private val registeredDependencyResolvers = mutableListOf<RegisteredDependencyResolver>()
private val registeredAdditionalArtifactResolvers = mutableListOf<RegisteredAdditionalArtifactResolver>()
private val registeredDependencyTransformers = mutableListOf<RegisteredDependencyTransformer>() private val registeredDependencyTransformers = mutableListOf<RegisteredDependencyTransformer>()
private val registeredDependencyEffects = mutableListOf<RegisteredDependencyEffect>() private val registeredDependencyEffects = mutableListOf<RegisteredDependencyEffect>()
private val registeredExtrasSerializationExtensions = mutableListOf<IdeaKotlinExtrasSerializationExtension>() private val registeredExtrasSerializationExtensions = mutableListOf<IdeaKotlinExtrasSerializationExtension>()
@@ -82,6 +84,20 @@ internal class IdeMultiplatformImportImpl(
) )
} }
@ExternalKotlinTargetApi
override fun registerAdditionalArtifactResolver(
resolver: IdeAdditionalArtifactResolver,
constraint: SourceSetConstraint,
phase: AdditionalArtifactResolutionPhase,
level: AdditionalArtifactResolutionLevel
) {
registeredAdditionalArtifactResolvers.add(
RegisteredAdditionalArtifactResolver(
extension.project.kotlinIdeMultiplatformImportStatistics, resolver, constraint, phase, level
)
)
}
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
override fun registerDependencyEffect(effect: IdeDependencyEffect, constraint: SourceSetConstraint) { override fun registerDependencyEffect(effect: IdeDependencyEffect, constraint: SourceSetConstraint) {
registeredDependencyEffects.add( registeredDependencyEffects.add(
@@ -95,9 +111,11 @@ internal class IdeMultiplatformImportImpl(
} }
private fun createDependencyResolver(): IdeDependencyResolver { private fun createDependencyResolver(): IdeDependencyResolver {
return IdeDependencyResolver(DependencyResolutionPhase.values().map { phase -> return IdeDependencyResolver(
createDependencyResolver(phase) DependencyResolutionPhase.values().map { phase -> createDependencyResolver(phase) }
}).withTransformer(createDependencyTransformer()) )
.withAdditionalArtifactResolver(createAdditionalArtifactsResolver())
.withTransformer(createDependencyTransformer())
.withEffect(createDependencyEffect()) .withEffect(createDependencyEffect())
} }
@@ -119,6 +137,25 @@ internal class IdeMultiplatformImportImpl(
emptySet() emptySet()
} }
private fun createAdditionalArtifactsResolver() = IdeAdditionalArtifactResolver(
AdditionalArtifactResolutionPhase.values().map { phase -> createAdditionalArtifactsResolver(phase) })
private fun createAdditionalArtifactsResolver(phase: AdditionalArtifactResolutionPhase) =
IdeAdditionalArtifactResolver resolve@{ sourceSet, dependencies ->
val applicableResolvers = registeredAdditionalArtifactResolvers
.filter { it.phase == phase }
.filter { it.constraint(sourceSet) }
.groupBy { it.level }
AdditionalArtifactResolutionLevel.values().reversed().forEach { level ->
val resolvers = applicableResolvers[level].orEmpty()
if (resolvers.isNotEmpty()) {
resolvers.forEach { resolver -> resolver.resolve(sourceSet, dependencies) }
return@resolve
}
}
}
private fun createDependencyTransformer(): IdeDependencyTransformer { private fun createDependencyTransformer(): IdeDependencyTransformer {
return IdeDependencyTransformer(DependencyTransformationPhase.values().map { phase -> return IdeDependencyTransformer(DependencyTransformationPhase.values().map { phase ->
createDependencyTransformer(phase) createDependencyTransformer(phase)
@@ -202,4 +239,18 @@ internal class IdeMultiplatformImportImpl(
} }
} }
} }
private class RegisteredAdditionalArtifactResolver(
private val statistics: IdeMultiplatformImportStatistics,
private val resolver: IdeAdditionalArtifactResolver,
val constraint: SourceSetConstraint,
val phase: AdditionalArtifactResolutionPhase,
val level: AdditionalArtifactResolutionLevel
) : IdeAdditionalArtifactResolver {
override fun resolve(sourceSet: KotlinSourceSet, dependencies: Set<IdeaKotlinDependency>) {
runCatching { measureTimeMillis { resolver.resolve(sourceSet, dependencies) } }
.onFailure { logger.error("e: ${resolver::class.java.name} failed on ${IdeaKotlinSourceCoordinates(sourceSet)}", it) }
.onSuccess { statistics.addExecutionTime(resolver::class.java, it) }
}
}
} }
@@ -7,17 +7,18 @@ package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ModuleComponentIdentifier import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.artifacts.result.ArtifactResolutionResult
import org.gradle.api.artifacts.result.ResolvedArtifactResult import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.component.Artifact
import org.gradle.jvm.JvmLibrary import org.gradle.jvm.JvmLibrary
import org.gradle.language.base.artifact.SourcesArtifact import org.gradle.language.base.artifact.SourcesArtifact
import org.gradle.language.java.artifact.JavadocArtifact import org.gradle.language.java.artifact.JavadocArtifact
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.extras.documentationClasspath
import org.jetbrains.kotlin.gradle.idea.tcs.extras.sourcesClasspath
import org.jetbrains.kotlin.gradle.idea.tcs.isKotlinCompileBinaryType
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver import org.jetbrains.kotlin.gradle.plugin.ide.IdeAdditionalArtifactResolver
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinBinaryCoordinates import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinBinaryCoordinates
import org.jetbrains.kotlin.gradle.plugin.mpp.internal import org.jetbrains.kotlin.gradle.plugin.mpp.internal
import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
@@ -32,8 +33,12 @@ import org.jetbrains.kotlin.gradle.plugin.sources.project
* *
* cc Anton Lakotka, Sebastian Sellmair * cc Anton Lakotka, Sebastian Sellmair
*/ */
internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeDependencyResolver { internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeAdditionalArtifactResolver {
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> { override fun resolve(sourceSet: KotlinSourceSet, dependencies: Set<IdeaKotlinDependency>) {
val binaryDependencies = dependencies.filterIsInstance<IdeaKotlinResolvedBinaryDependency>()
.filter { dependency -> dependency.isKotlinCompileBinaryType }
.groupBy { dependency -> dependency.coordinates?.copy(sourceSetName = null) }
val project = sourceSet.project val project = sourceSet.project
val configuration = selectConfiguration(sourceSet) val configuration = selectConfiguration(sourceSet)
val resolutionResult = project.dependencies.createArtifactResolutionQuery() val resolutionResult = project.dependencies.createArtifactResolutionQuery()
@@ -41,25 +46,29 @@ internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeD
.withArtifacts(JvmLibrary::class.java, SourcesArtifact::class.java, JavadocArtifact::class.java) .withArtifacts(JvmLibrary::class.java, SourcesArtifact::class.java, JavadocArtifact::class.java)
.execute() .execute()
return resolve(resolutionResult, SourcesArtifact::class.java, IdeaKotlinDependency.SOURCES_BINARY_TYPE) + val sourcesArtifacts = resolutionResult.resolvedComponents.flatMap { resolved ->
resolve(resolutionResult, JavadocArtifact::class.java, IdeaKotlinDependency.DOCUMENTATION_BINARY_TYPE) resolved.getArtifacts(SourcesArtifact::class.java).filterIsInstance<ResolvedArtifactResult>()
} }
fun resolve( sourcesArtifacts.forEach { artifact ->
resolutionResult: ArtifactResolutionResult, artifactType: Class<out Artifact>, binaryType: String val artifactId = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return@forEach
): Set<IdeaKotlinResolvedBinaryDependency> { val artifactCoordinates = IdeaKotlinBinaryCoordinates(artifactId)
return resolutionResult.resolvedComponents.flatMap { resolved -> binaryDependencies[artifactCoordinates]?.forEach { dependency ->
resolved.getArtifacts(artifactType) dependency.sourcesClasspath.add(artifact.file)
.filterIsInstance<ResolvedArtifactResult>() }
.mapNotNull { artifact -> }
val id = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return@mapNotNull null
IdeaKotlinResolvedBinaryDependency( val javadocArtifacts = resolutionResult.resolvedComponents.flatMap { resolved ->
coordinates = IdeaKotlinBinaryCoordinates(id), resolved.getArtifacts(JavadocArtifact::class.java).filterIsInstance<ResolvedArtifactResult>()
binaryType = binaryType, }
binaryFile = artifact.file
) javadocArtifacts.forEach { artifact ->
} val artifactId = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return@forEach
}.toSet() val artifactCoordinates = IdeaKotlinBinaryCoordinates(artifactId)
binaryDependencies[artifactCoordinates]?.forEach { dependency ->
dependency.documentationClasspath.add(artifact.file)
}
}
} }
private fun selectConfiguration(sourceSet: KotlinSourceSet): Configuration { private fun selectConfiguration(sourceSet: KotlinSourceSet): Configuration {
@@ -15,6 +15,7 @@ import org.gradle.internal.component.local.model.OpaqueComponentArtifactIdentifi
import org.gradle.internal.resolve.ModuleVersionResolveException import org.gradle.internal.resolve.ModuleVersionResolveException
import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi
import org.jetbrains.kotlin.gradle.idea.tcs.* import org.jetbrains.kotlin.gradle.idea.tcs.*
import org.jetbrains.kotlin.gradle.idea.tcs.extras.artifactsClasspath
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
@@ -36,7 +37,7 @@ import org.jetbrains.kotlin.tooling.core.mutableExtrasOf
@ExternalKotlinTargetApi @ExternalKotlinTargetApi
class IdeBinaryDependencyResolver( class IdeBinaryDependencyResolver(
private val binaryType: String = IdeaKotlinDependency.CLASSPATH_BINARY_TYPE, private val binaryType: String = IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE,
private val artifactResolutionStrategy: ArtifactResolutionStrategy = ArtifactResolutionStrategy.Compilation() private val artifactResolutionStrategy: ArtifactResolutionStrategy = ArtifactResolutionStrategy.Compilation()
) : IdeDependencyResolver { ) : IdeDependencyResolver {
@@ -100,18 +101,17 @@ class IdeBinaryDependencyResolver(
is ProjectComponentIdentifier -> { is ProjectComponentIdentifier -> {
IdeaKotlinProjectArtifactDependency( IdeaKotlinProjectArtifactDependency(
type = IdeaKotlinSourceDependency.Type.Regular, type = IdeaKotlinSourceDependency.Type.Regular,
coordinates = IdeaKotlinProjectArtifactCoordinates( coordinates = IdeaKotlinProjectCoordinates(componentId)
project = IdeaKotlinProjectCoordinates(componentId), ).apply {
artifactFile = artifact.file artifactsClasspath.add(artifact.file)
) }
)
} }
is ModuleComponentIdentifier -> { is ModuleComponentIdentifier -> {
IdeaKotlinResolvedBinaryDependency( IdeaKotlinResolvedBinaryDependency(
coordinates = IdeaKotlinBinaryCoordinates(componentId), coordinates = IdeaKotlinBinaryCoordinates(componentId),
binaryType = binaryType, binaryType = binaryType,
binaryFile = artifact.file, classpath = IdeaKotlinClasspath(artifact.file),
) )
} }
@@ -123,7 +123,7 @@ class IdeBinaryDependencyResolver(
module = componentId.libraryName, module = componentId.libraryName,
version = null, sourceSetName = null version = null, sourceSetName = null
), ),
binaryFile = artifact.file classpath = IdeaKotlinClasspath(artifact.file)
) )
} }
@@ -12,7 +12,7 @@ import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.attributes.Category import org.gradle.api.attributes.Category
import org.gradle.api.attributes.Usage import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.java.TargetJvmEnvironment import org.gradle.api.attributes.java.TargetJvmEnvironment
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryDependency
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.usageByName import org.jetbrains.kotlin.gradle.plugin.usageByName
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.gradle.utils.named
*/ */
internal fun IdeJvmAndAndroidPlatformBinaryDependencyResolver(project: Project): IdeDependencyResolver = internal fun IdeJvmAndAndroidPlatformBinaryDependencyResolver(project: Project): IdeDependencyResolver =
IdeBinaryDependencyResolver( IdeBinaryDependencyResolver(
binaryType = IdeaKotlinDependency.CLASSPATH_BINARY_TYPE, binaryType = IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE,
artifactResolutionStrategy = IdeBinaryDependencyResolver.ArtifactResolutionStrategy.PlatformLikeSourceSet( artifactResolutionStrategy = IdeBinaryDependencyResolver.ArtifactResolutionStrategy.PlatformLikeSourceSet(
setupPlatformResolutionAttributes = { setupPlatformResolutionAttributes = {
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(Usage.JAVA_API)) attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(Usage.JAVA_API))
@@ -9,14 +9,16 @@ package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers
import org.gradle.api.attributes.Category import org.gradle.api.attributes.Category
import org.gradle.api.attributes.DocsType import org.gradle.api.attributes.DocsType
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.plugin.ide.IdeAdditionalArtifactResolver
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.ide.asAdditionalArtifactResolver
import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
import org.jetbrains.kotlin.gradle.plugin.sources.internal import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.plugin.sources.project import org.jetbrains.kotlin.gradle.plugin.sources.project
import org.jetbrains.kotlin.gradle.utils.named import org.jetbrains.kotlin.gradle.utils.named
internal fun IdeMetadataSourcesResolver(): IdeBinaryDependencyResolver = IdeBinaryDependencyResolver( internal fun IdeMetadataSourcesResolver(): IdeAdditionalArtifactResolver = IdeBinaryDependencyResolver(
binaryType = IdeaKotlinDependency.SOURCES_BINARY_TYPE, binaryType = IdeDependencyResolver.SOURCES_BINARY_TYPE,
artifactResolutionStrategy = IdeBinaryDependencyResolver.ArtifactResolutionStrategy.ResolvableConfiguration( artifactResolutionStrategy = IdeBinaryDependencyResolver.ArtifactResolutionStrategy.ResolvableConfiguration(
configurationSelector = { it.internal.resolvableMetadataConfiguration }, configurationSelector = { it.internal.resolvableMetadataConfiguration },
setupArtifactViewAttributes = { setupArtifactViewAttributes = {
@@ -24,4 +26,4 @@ internal fun IdeMetadataSourcesResolver(): IdeBinaryDependencyResolver = IdeBina
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, it.project.objects.named(DocsType.SOURCES)) attribute(DocsType.DOCS_TYPE_ATTRIBUTE, it.project.objects.named(DocsType.SOURCES))
} }
) )
) ).asAdditionalArtifactResolver()
@@ -9,15 +9,15 @@ import org.gradle.api.Project
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging import org.gradle.api.logging.Logging
import org.jetbrains.kotlin.commonizer.KonanDistribution import org.jetbrains.kotlin.commonizer.KonanDistribution
import org.jetbrains.kotlin.commonizer.sourcesDir
import org.jetbrains.kotlin.commonizer.stdlib import org.jetbrains.kotlin.commonizer.stdlib
import org.jetbrains.kotlin.compilerRunner.konanHome import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.compilerRunner.konanVersion import org.jetbrains.kotlin.compilerRunner.konanVersion
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates import org.jetbrains.kotlin.gradle.idea.tcs.*
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeDistribution import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeDistribution
import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeStdlib import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeStdlib
import org.jetbrains.kotlin.gradle.idea.tcs.extras.klibExtra import org.jetbrains.kotlin.gradle.idea.tcs.extras.klibExtra
import org.jetbrains.kotlin.gradle.idea.tcs.extras.sourcesClasspath
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.ide.KlibExtra import org.jetbrains.kotlin.gradle.plugin.ide.KlibExtra
@@ -30,11 +30,12 @@ internal object IdeNativeStdlibDependencyResolver : IdeDependencyResolver {
private val logger: Logger = Logging.getLogger(IdeNativePlatformDependencyResolver::class.java) private val logger: Logger = Logging.getLogger(IdeNativePlatformDependencyResolver::class.java)
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> { override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> {
val binaryFile = KonanDistribution(sourceSet.project.konanHome).stdlib val konanDistribution = KonanDistribution(sourceSet.project.konanHome)
val stdlibFile = KonanDistribution(sourceSet.project.konanHome).stdlib
val klibExtra = try { val klibExtra = try {
val kotlinLibrary = resolveSingleFileKlib( val kotlinLibrary = resolveSingleFileKlib(
libraryFile = File(binaryFile.absolutePath), libraryFile = File(stdlibFile.absolutePath),
strategy = ToolingSingleFileKlibResolveStrategy strategy = ToolingSingleFileKlibResolveStrategy
) )
@@ -46,13 +47,17 @@ internal object IdeNativeStdlibDependencyResolver : IdeDependencyResolver {
return setOf( return setOf(
IdeaKotlinResolvedBinaryDependency( IdeaKotlinResolvedBinaryDependency(
binaryType = IdeaKotlinDependency.CLASSPATH_BINARY_TYPE, binaryType = IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE,
binaryFile = binaryFile, classpath = IdeaKotlinClasspath(stdlibFile),
coordinates = nativeStdlibCoordinates(sourceSet.project) coordinates = nativeStdlibCoordinates(sourceSet.project)
).apply { ).apply {
this.isNativeDistribution = true this.isNativeDistribution = true
this.isNativeStdlib = true this.isNativeStdlib = true
this.klibExtra = klibExtra this.klibExtra = klibExtra
this.sourcesClasspath += konanDistribution.sourcesDir.listFiles().orEmpty()
/* Ignore org.jetbrains.kotlinx. in this case */
.filter { file -> file.name.startsWith("kotlin") }
.ifEmpty { return emptySet() }
} }
) )
} }
@@ -1,35 +0,0 @@
/*
* 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.ide.dependencyResolvers
import org.jetbrains.kotlin.commonizer.KonanDistribution
import org.jetbrains.kotlin.commonizer.sourcesDir
import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeDistribution
import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeStdlib
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.sources.project
internal object IdeNativeStdlibSourcesResolver : IdeDependencyResolver {
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> {
return KonanDistribution(sourceSet.project.konanHome).sourcesDir.listFiles().orEmpty()
/* Ignore org.jetbrains.kotlinx. in this case */
.filter { file -> file.name.startsWith("kotlin") }
.map { file ->
IdeaKotlinResolvedBinaryDependency(
binaryType = IdeaKotlinDependency.SOURCES_BINARY_TYPE,
binaryFile = file,
coordinates = IdeNativeStdlibDependencyResolver.nativeStdlibCoordinates(sourceSet.project)
).apply {
isNativeStdlib = true
isNativeDistribution = true
}
}.toSet()
}
}
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers
import org.gradle.api.artifacts.component.ModuleComponentIdentifier import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinClasspath
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
@@ -30,8 +32,8 @@ internal object IdeOriginalMetadataDependencyResolver : IdeDependencyResolver {
return artifactsView.artifacts.mapNotNull { artifact -> return artifactsView.artifacts.mapNotNull { artifact ->
val moduleId = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return@mapNotNull null val moduleId = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return@mapNotNull null
IdeaKotlinResolvedBinaryDependency( IdeaKotlinResolvedBinaryDependency(
binaryType = IdeaKotlinDependency.CLASSPATH_BINARY_TYPE, binaryType = IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE,
binaryFile = artifact.file, classpath = IdeaKotlinClasspath(artifact.file),
coordinates = IdeaKotlinBinaryCoordinates(moduleId) coordinates = IdeaKotlinBinaryCoordinates(moduleId)
) )
}.toSet() }.toSet()
@@ -9,12 +9,12 @@ package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers
import org.gradle.api.attributes.Category import org.gradle.api.attributes.Category
import org.gradle.api.attributes.DocsType import org.gradle.api.attributes.DocsType
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.sources.project import org.jetbrains.kotlin.gradle.plugin.sources.project
import org.jetbrains.kotlin.gradle.utils.named import org.jetbrains.kotlin.gradle.utils.named
internal fun IdePlatformSourcesResolver(): IdeBinaryDependencyResolver = IdeBinaryDependencyResolver( internal fun IdePlatformSourcesResolver(): IdeBinaryDependencyResolver = IdeBinaryDependencyResolver(
binaryType = IdeaKotlinDependency.SOURCES_BINARY_TYPE, binaryType = IdeDependencyResolver.SOURCES_BINARY_TYPE,
artifactResolutionStrategy = IdeBinaryDependencyResolver.ArtifactResolutionStrategy.Compilation( artifactResolutionStrategy = IdeBinaryDependencyResolver.ArtifactResolutionStrategy.Compilation(
setupArtifactViewAttributes = { setupArtifactViewAttributes = {
attribute(Category.CATEGORY_ATTRIBUTE, it.project.objects.named(Category.DOCUMENTATION)) attribute(Category.CATEGORY_ATTRIBUTE, it.project.objects.named(Category.DOCUMENTATION))
@@ -6,9 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers
import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates import org.jetbrains.kotlin.gradle.idea.tcs.*
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets
@@ -42,8 +40,8 @@ internal object IdeTransformedMetadataDependencyResolver : IdeDependencyResolver
} }
IdeaKotlinResolvedBinaryDependency( IdeaKotlinResolvedBinaryDependency(
binaryType = IdeaKotlinDependency.CLASSPATH_BINARY_TYPE, binaryType = IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE,
binaryFile = metadataLibraryOutputFile, classpath = IdeaKotlinClasspath(metadataLibraryOutputFile),
extras = mutableExtrasOf(), extras = mutableExtrasOf(),
coordinates = IdeaKotlinBinaryCoordinates( coordinates = IdeaKotlinBinaryCoordinates(
group = metadataProvider.moduleDependencyIdentifier.groupId ?: "", group = metadataProvider.moduleDependencyIdentifier.groupId ?: "",
@@ -11,7 +11,8 @@ import org.jetbrains.kotlin.commonizer.CommonizerTarget
import org.jetbrains.kotlin.commonizer.identityString import org.jetbrains.kotlin.commonizer.identityString
import org.jetbrains.kotlin.compilerRunner.konanVersion import org.jetbrains.kotlin.compilerRunner.konanVersion
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinClasspath
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeDistribution import org.jetbrains.kotlin.gradle.idea.tcs.extras.isNativeDistribution
import org.jetbrains.kotlin.gradle.idea.tcs.extras.klibExtra import org.jetbrains.kotlin.gradle.idea.tcs.extras.klibExtra
@@ -35,8 +36,8 @@ internal fun Project.resolveNativeDistributionLibraryForIde(
} }
return IdeaKotlinResolvedBinaryDependency( return IdeaKotlinResolvedBinaryDependency(
binaryType = IdeaKotlinDependency.CLASSPATH_BINARY_TYPE, binaryType = IdeaKotlinBinaryDependency.KOTLIN_COMPILE_BINARY_TYPE,
binaryFile = library, classpath = IdeaKotlinClasspath(library),
coordinates = IdeaKotlinBinaryCoordinates( coordinates = IdeaKotlinBinaryCoordinates(
group = "org.jetbrains.kotlin.native", group = "org.jetbrains.kotlin.native",
module = resolvedLibrary.packageFqName ?: resolvedLibrary.shortName ?: resolvedLibrary.uniqueName, module = resolvedLibrary.packageFqName ?: resolvedLibrary.shortName ?: resolvedLibrary.uniqueName,
@@ -1,48 +0,0 @@
/*
* 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.ide.dependencyTransformers
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency.Companion.CLASSPATH_BINARY_TYPE
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency.Companion.DOCUMENTATION_BINARY_TYPE
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency.Companion.SOURCES_BINARY_TYPE
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyTransformer
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.IdeArtifactResolutionQuerySourcesAndDocumentationResolver
/**
* Filters out -sources.jar and -javadoc.jar dependencies that are actually not necessary for the KotlinSourceSet:
* This counter-acts the fact that the [IdeArtifactResolutionQuerySourcesAndDocumentationResolver] is potentially "over-resolving" sources
* for multiplatform libraries.
*/
internal object UnusedSourcesAndDocumentationFilter : IdeDependencyTransformer {
override fun transform(sourceSet: KotlinSourceSet, dependencies: Set<IdeaKotlinDependency>): Set<IdeaKotlinDependency> {
val binaryDependencies = dependencies.filterIsInstance<IdeaKotlinResolvedBinaryDependency>()
val classpathBinaryCoordinates = binaryDependencies.filter { it.binaryType == CLASSPATH_BINARY_TYPE }
.mapNotNull { it.coordinates?.relevantString() }
.toSet()
val unusedDependencies = binaryDependencies.filter { it.binaryType in sourcesAndDocumentationBinaryTypes }
.filter { it.coordinates?.relevantString() !in classpathBinaryCoordinates }
.toSet()
return dependencies - unusedDependencies
}
private val sourcesAndDocumentationBinaryTypes = setOf(SOURCES_BINARY_TYPE, DOCUMENTATION_BINARY_TYPE)
/**
* This filter only works based upon group, module and version.
* We can consider the sourceSetName to be irrelevant, since we do not have -sources.jar published on a 'per source set' level.
*/
private fun IdeaKotlinBinaryCoordinates.relevantString(): String = "$group:$module:$version"
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.ide package org.jetbrains.kotlin.gradle.plugin.ide
import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.idea.proto.tcs.IdeaKotlinClasspathSerializer
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinBooleanExtrasSerializer import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinBooleanExtrasSerializer
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtension import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtension
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializer.Companion.javaIoSerializable import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializer.Companion.javaIoSerializable
@@ -20,4 +21,7 @@ val kotlinExtrasSerialization = IdeaKotlinExtrasSerializationExtension {
register(isNativeDistributionKey, IdeaKotlinBooleanExtrasSerializer) register(isNativeDistributionKey, IdeaKotlinBooleanExtrasSerializer)
register(isNativeStdlibKey, IdeaKotlinBooleanExtrasSerializer) register(isNativeStdlibKey, IdeaKotlinBooleanExtrasSerializer)
register(isCommonizedKey, IdeaKotlinBooleanExtrasSerializer) register(isCommonizedKey, IdeaKotlinBooleanExtrasSerializer)
register(sourcesClasspathKey, IdeaKotlinClasspathSerializer)
register(documentationClasspathKey, IdeaKotlinClasspathSerializer)
register(projectArtifactsClasspathKey, IdeaKotlinClasspathSerializer)
} }
@@ -13,7 +13,9 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.enableDefaultStdlibDependency import org.jetbrains.kotlin.gradle.enableDefaultStdlibDependency
import org.jetbrains.kotlin.gradle.enableDependencyVerification import org.jetbrains.kotlin.gradle.enableDependencyVerification
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.idea.tcs.isSourcesBinaryType import org.jetbrains.kotlin.gradle.idea.tcs.extras.documentationClasspathKey
import org.jetbrains.kotlin.gradle.idea.tcs.extras.sourcesClasspath
import org.jetbrains.kotlin.gradle.idea.tcs.extras.sourcesClasspathKey
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.assertMatches import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.assertMatches
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.binaryCoordinates import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.binaryCoordinates
import org.jetbrains.kotlin.gradle.kpm.idea.mavenCentralCacheRedirector import org.jetbrains.kotlin.gradle.kpm.idea.mavenCentralCacheRedirector
@@ -57,36 +59,36 @@ class IdeSourcesAndDocumentationResolutionTest {
fun resolveDependencySources(sourceSet: KotlinSourceSet): List<IdeaKotlinResolvedBinaryDependency> = fun resolveDependencySources(sourceSet: KotlinSourceSet): List<IdeaKotlinResolvedBinaryDependency> =
project.kotlinIdeMultiplatformImport.resolveDependencies(sourceSet) project.kotlinIdeMultiplatformImport.resolveDependencies(sourceSet)
.filterIsInstance<IdeaKotlinResolvedBinaryDependency>() .filterIsInstance<IdeaKotlinResolvedBinaryDependency>()
.filter { it.isSourcesBinaryType } .filter { it.sourcesClasspath.isNotEmpty() }
/* Check commonMain&commonTest */ /* Check commonMain&commonTest */
run { run {
val expectedDependencies = listOf( val expectedDependencies = listOf(
binaryCoordinates("com.arkivanov.mvikotlin:mvikotlin:3.0.2"), binaryCoordinates("com.arkivanov.mvikotlin:mvikotlin:3.0.2:commonMain"),
binaryCoordinates("com.arkivanov.essenty:lifecycle:0.4.2"), binaryCoordinates("com.arkivanov.essenty:lifecycle:0.4.2:commonMain"),
binaryCoordinates("com.arkivanov.essenty:instance-keeper:0.4.2"), binaryCoordinates("com.arkivanov.essenty:instance-keeper:0.4.2:commonMain"),
) )
val resolvedDependencies = resolveDependencySources(commonMain) val resolvedDependencies = resolveDependencySources(commonMain)
resolvedDependencies.assertMatches(expectedDependencies) resolvedDependencies.assertMatches(expectedDependencies)
resolveDependencySources(commonTest).assertMatches(resolvedDependencies) resolveDependencySources(commonTest).assertMatches(resolvedDependencies)
resolvedDependencies.assertFilesEndWith("-sources.jar") resolvedDependencies.assertSourcesFilesEndWith("-sources.jar")
} }
/* Check nativeMain&nativeTest */ /* Check nativeMain&nativeTest */
run { run {
val expectedDependencies = listOf( val expectedDependencies = listOf(
binaryCoordinates("com.arkivanov.mvikotlin:mvikotlin:3.0.2"), binaryCoordinates("com.arkivanov.mvikotlin:mvikotlin:3.0.2:commonMain"),
binaryCoordinates("com.arkivanov.essenty:lifecycle:0.4.2"), binaryCoordinates("com.arkivanov.mvikotlin:mvikotlin:3.0.2:jsNativeMain"),
binaryCoordinates("com.arkivanov.essenty:instance-keeper:0.4.2"), binaryCoordinates("com.arkivanov.essenty:lifecycle:0.4.2:commonMain"),
binaryCoordinates("com.arkivanov.essenty:instance-keeper:0.4.2:commonMain"),
IdeNativeStdlibDependencyResolver.nativeStdlibCoordinates(project) IdeNativeStdlibDependencyResolver.nativeStdlibCoordinates(project)
) )
val resolvedDependencies = resolveDependencySources(nativeMain) val resolvedDependencies = resolveDependencySources(nativeMain)
resolvedDependencies.assertMatches(expectedDependencies) resolvedDependencies.assertMatches(expectedDependencies)
resolveDependencySources(nativeTest).assertMatches(resolvedDependencies) resolveDependencySources(nativeTest).assertMatches(resolvedDependencies)
resolvedDependencies.assertFilesEndWith("-sources.jar", "-sources.zip") resolvedDependencies.assertSourcesFilesEndWith("-sources.jar", "-sources.zip")
} }
/* Check linuxX64Main and linuxX64Test */ /* Check linuxX64Main and linuxX64Test */
@@ -114,16 +116,25 @@ class IdeSourcesAndDocumentationResolutionTest {
val resolvedDependencies = resolveDependencySources(linuxX64Main) val resolvedDependencies = resolveDependencySources(linuxX64Main)
resolvedDependencies.assertMatches(expectedDependencies) resolvedDependencies.assertMatches(expectedDependencies)
resolveDependencySources(linuxX64Test).assertMatches(resolvedDependencies) resolveDependencySources(linuxX64Test).withSanitisedExtras().assertMatches(resolvedDependencies.withSanitisedExtras())
resolvedDependencies.assertFilesEndWith("-sources.jar", "-sources.zip") resolvedDependencies.assertSourcesFilesEndWith("-sources.jar", "-sources.zip")
} }
} }
} }
private fun Iterable<IdeaKotlinResolvedBinaryDependency>.assertFilesEndWith(vararg suffixes: String) { private fun Iterable<IdeaKotlinResolvedBinaryDependency>.withSanitisedExtras() = onEach { dependency ->
val keysToKeep = setOf(sourcesClasspathKey, documentationClasspathKey)
(dependency.extras.keys - keysToKeep).forEach { keyToRemove ->
dependency.extras.remove(keyToRemove)
}
}
private fun Iterable<IdeaKotlinResolvedBinaryDependency>.assertSourcesFilesEndWith(vararg suffixes: String) {
forEach { dependency -> forEach { dependency ->
if (suffixes.none { suffix -> dependency.binaryFile.path.endsWith(suffix) }) { dependency.sourcesClasspath.forEach { sourcesFile ->
fail("Expected binaryFile to end with one of ${suffixes.toList()}. Found: ${dependency.binaryFile}") if (suffixes.none { suffix -> sourcesFile.path.endsWith(suffix) }) {
fail("Expected binaryFile to end with one of ${suffixes.toList()}. Found: ${sourcesFile}")
}
} }
} }
} }