[Gradle] Initial port of IdeaKpmProjectModelBuilder into TCS IdeMultiplatformImport
KT-54825
This commit is contained in:
committed by
Space Team
parent
c727dbb8ca
commit
405c94e0bb
+55
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.tooling.core.Extras
|
||||||
|
import java.io.File
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
sealed class IdeDependency {
|
||||||
|
abstract val coordinates: IdeDependencyCoordinates?
|
||||||
|
abstract val extras: Extras
|
||||||
|
|
||||||
|
/* Reflection helper */
|
||||||
|
|
||||||
|
val isSourceDependency: Boolean get() = this is IdeSourceDependency
|
||||||
|
val isBinaryDependency: Boolean get() = this is IdeBinaryDependency
|
||||||
|
val isResolvedBinaryDependency: Boolean get() = this is IdeResolvedBinaryDependency
|
||||||
|
val isUnresolvedBinaryDependency: Boolean get() = this is IdeUnresolvedBinaryDependency
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val CLASSPATH_BINARY_TYPE = "org.jetbrains.kotlin.gradle.plugin.ide.IdeDependency.classpathBinaryType"
|
||||||
|
const val SOURCES_BINARY_TYPE = "org.jetbrains.kotlin.gradle.plugin.ide.IdeDependency.sourcesBinaryType"
|
||||||
|
const val DOCUMENTATION_BINARY_TYPE = "org.jetbrains.kotlin.gradle.plugin.ide.IdeDependency.documentationBinaryType"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class IdeSourceDependency(
|
||||||
|
val type: Type,
|
||||||
|
override val coordinates: IdeSourceCoordinates,
|
||||||
|
override val extras: Extras
|
||||||
|
) : IdeDependency() {
|
||||||
|
enum class Type : Serializable {
|
||||||
|
Regular, Friend, DependsOn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class IdeBinaryDependency : IdeDependency() {
|
||||||
|
abstract override val coordinates: IdeBinaryCoordinates?
|
||||||
|
}
|
||||||
|
|
||||||
|
data class IdeUnresolvedBinaryDependency(
|
||||||
|
val cause: String?,
|
||||||
|
override val coordinates: IdeBinaryCoordinates?,
|
||||||
|
override val extras: Extras
|
||||||
|
) : IdeBinaryDependency()
|
||||||
|
|
||||||
|
data class IdeResolvedBinaryDependency(
|
||||||
|
val binaryType: String,
|
||||||
|
val binaryFile: File,
|
||||||
|
override val extras: Extras,
|
||||||
|
override val coordinates: IdeBinaryCoordinates?
|
||||||
|
) : IdeBinaryDependency()
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
sealed class IdeDependencyCoordinates {
|
||||||
|
/* Reflection helpers */
|
||||||
|
val isBinaryCoordinates get() = this is IdeBinaryCoordinates
|
||||||
|
val isSourceCoordinates get() = this is IdeSourceCoordinates
|
||||||
|
}
|
||||||
|
|
||||||
|
data class IdeBinaryCoordinates(
|
||||||
|
val group: String,
|
||||||
|
val module: String,
|
||||||
|
val version: String?,
|
||||||
|
val sourceSetName: String?
|
||||||
|
) : IdeDependencyCoordinates()
|
||||||
|
|
||||||
|
data class IdeSourceCoordinates(
|
||||||
|
val buildId: String,
|
||||||
|
val projectPath: String,
|
||||||
|
val projectName: String,
|
||||||
|
val sourceSetName: String
|
||||||
|
) : IdeDependencyCoordinates()
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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.plugin.KotlinSourceSet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An [IdeDependencyEffect] is invoked last in the dependency resolution pipeline.
|
||||||
|
* It is not intended/capable of changing the resolution result, but can trigger side-effects, being sure
|
||||||
|
* that the dependency resolution result is final.
|
||||||
|
*/
|
||||||
|
fun interface IdeDependencyEffect {
|
||||||
|
operator fun invoke(sourceSet: KotlinSourceSet, dependencies: Set<IdeDependency>)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IdeDependencyResolver.withEffect(effect: IdeDependencyEffect) = IdeDependencyResolver { sourceSet ->
|
||||||
|
this@withEffect.resolve(sourceSet).also { dependencies -> effect(sourceSet, dependencies) }
|
||||||
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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.plugin.KotlinSourceSet
|
||||||
|
|
||||||
|
fun interface IdeDependencyResolver {
|
||||||
|
fun resolve(sourceSet: KotlinSourceSet): Set<IdeDependency>
|
||||||
|
|
||||||
|
object Empty : IdeDependencyResolver {
|
||||||
|
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeDependency> = emptySet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IdeDependencyResolver(
|
||||||
|
resolvers: Iterable<IdeDependencyResolver?>
|
||||||
|
): IdeDependencyResolver {
|
||||||
|
val resolversList = resolvers.filterNotNull()
|
||||||
|
if (resolversList.isEmpty()) return IdeDependencyResolver.Empty
|
||||||
|
return IdeCompositeDependencyResolver(resolversList)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IdeDependencyResolver(
|
||||||
|
vararg resolvers: IdeDependencyResolver?
|
||||||
|
): IdeDependencyResolver = IdeDependencyResolver(resolvers.toList())
|
||||||
|
|
||||||
|
|
||||||
|
operator fun IdeDependencyResolver.plus(other: IdeDependencyResolver): IdeDependencyResolver {
|
||||||
|
if (this is IdeCompositeDependencyResolver && other is IdeCompositeDependencyResolver)
|
||||||
|
return IdeCompositeDependencyResolver(this.children + other.children)
|
||||||
|
|
||||||
|
if (this is IdeCompositeDependencyResolver) {
|
||||||
|
return IdeCompositeDependencyResolver(this.children + other)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other is IdeCompositeDependencyResolver) {
|
||||||
|
return IdeCompositeDependencyResolver(listOf(this) + other.children)
|
||||||
|
}
|
||||||
|
return IdeCompositeDependencyResolver(listOf(this, other))
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IdeCompositeDependencyResolver(
|
||||||
|
val children: List<IdeDependencyResolver>
|
||||||
|
) : IdeDependencyResolver {
|
||||||
|
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeDependency> {
|
||||||
|
return children.flatMap { child -> child.resolve(sourceSet) }.toSet()
|
||||||
|
}
|
||||||
|
}
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.plugin.KotlinSourceSet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An [IdeDependencyTransformer] will be invoked after all [IdeDependencyResolver] finished.
|
||||||
|
* The transformation step is allowed to entirely modify the resolution result. Typical applications would be dependency filtering,
|
||||||
|
* or grouping. Adding additional dependencies might be harmful, since other transformers might not be able to see this additional
|
||||||
|
* dependency, running before the addition.
|
||||||
|
*
|
||||||
|
* Transformations can be scheduled in different phases see: [IdeMultiplatformImport.DependencyTransformationPhase]
|
||||||
|
*/
|
||||||
|
fun interface IdeDependencyTransformer {
|
||||||
|
fun transform(sourceSet: KotlinSourceSet, dependencies: Set<IdeDependency>): Set<IdeDependency>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IdeDependencyResolver.withTransformer(transformer: IdeDependencyTransformer) = IdeDependencyResolver { sourceSet ->
|
||||||
|
transformer.transform(sourceSet, this@withTransformer.resolve(sourceSet))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IdeDependencyTransformer(
|
||||||
|
transformers: List<IdeDependencyTransformer?>
|
||||||
|
): IdeDependencyTransformer = IdeCompositeDependencyTransformer(transformers.filterNotNull())
|
||||||
|
|
||||||
|
fun IdeDependencyTransformer(
|
||||||
|
vararg transformers: IdeDependencyTransformer?
|
||||||
|
): IdeDependencyTransformer = IdeDependencyTransformer(transformers.toList())
|
||||||
|
|
||||||
|
operator fun IdeDependencyTransformer.plus(other: IdeDependencyTransformer):
|
||||||
|
IdeDependencyTransformer {
|
||||||
|
if (this is IdeCompositeDependencyTransformer && other is IdeCompositeDependencyTransformer) {
|
||||||
|
return IdeCompositeDependencyTransformer(this.transformers + other.transformers)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this is IdeCompositeDependencyTransformer) {
|
||||||
|
return IdeCompositeDependencyTransformer(this.transformers + other)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other is IdeCompositeDependencyTransformer) {
|
||||||
|
return IdeCompositeDependencyTransformer(listOf(this) + other.transformers)
|
||||||
|
}
|
||||||
|
|
||||||
|
return IdeCompositeDependencyTransformer(listOf(this, other))
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IdeCompositeDependencyTransformer(
|
||||||
|
val transformers: List<IdeDependencyTransformer>
|
||||||
|
) : IdeDependencyTransformer {
|
||||||
|
override fun transform(
|
||||||
|
sourceSet: KotlinSourceSet, dependencies: Set<IdeDependency>
|
||||||
|
): Set<IdeDependency> {
|
||||||
|
return transformers.fold(dependencies) { currentDependencies, transformer -> transformer.transform(sourceSet, currentDependencies) }
|
||||||
|
}
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.tooling.core.Extras
|
||||||
|
|
||||||
|
interface IdeExtrasSerializationExtension {
|
||||||
|
fun <T : Any> serializer(key: Extras.Key<T>): IdeExtrasSerializer<T>?
|
||||||
|
|
||||||
|
object Empty : IdeExtrasSerializationExtension {
|
||||||
|
override fun <T : Any> serializer(key: Extras.Key<T>): IdeExtrasSerializer<T>? = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IdeExtrasSerializationExtensionBuilder {
|
||||||
|
fun <T : Any> register(key: Extras.Key<T>, serializer: IdeExtrasSerializer<T>)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IdeExtrasSerializationExtension(
|
||||||
|
builder: IdeExtrasSerializationExtensionBuilder.() -> Unit
|
||||||
|
): IdeExtrasSerializationExtension {
|
||||||
|
return IdeaKpmExtrasSerializationExtensionImpl(
|
||||||
|
IdeaExtrasSerializationExtensionBuilderImpl().apply(builder).serializers
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IdeaExtrasSerializationExtensionBuilderImpl : IdeExtrasSerializationExtensionBuilder {
|
||||||
|
val serializers = mutableMapOf<Extras.Key<*>, IdeExtrasSerializer<*>>()
|
||||||
|
|
||||||
|
override fun <T : Any> register(key: Extras.Key<T>, serializer: IdeExtrasSerializer<T>) {
|
||||||
|
serializers[key] = serializer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class IdeaKpmExtrasSerializationExtensionImpl(
|
||||||
|
private val map: Map<Extras.Key<*>, IdeExtrasSerializer<*>>
|
||||||
|
) : IdeExtrasSerializationExtension {
|
||||||
|
override fun <T : Any> serializer(key: Extras.Key<T>): IdeExtrasSerializer<T>? {
|
||||||
|
@Suppress("unchecked_cast")
|
||||||
|
return map[key] as? IdeExtrasSerializer<T>
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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 kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
|
interface IdeExtrasSerializer<T : Any> {
|
||||||
|
fun serialize(context: IdeSerializationContext, value: T): ByteArray?
|
||||||
|
fun deserialize(context: IdeSerializationContext, data: ByteArray): T?
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Returns a [IdeExtrasSerializer] based upon [java.io.Serializable]
|
||||||
|
*/
|
||||||
|
fun <T : Any> javaIoSerializable(clazz: KClass<T>): IdeExtrasSerializer<T> {
|
||||||
|
return IdeJavaIoSerializableExtrasSerializer(clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> javaIoSerializable(): IdeExtrasSerializer<T> {
|
||||||
|
return javaIoSerializable(T::class)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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 java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.ObjectInputStream
|
||||||
|
import java.io.ObjectOutputStream
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
internal class IdeJavaIoSerializableExtrasSerializer<T : Any>(
|
||||||
|
private val clazz: KClass<T>
|
||||||
|
) : IdeExtrasSerializer<T> {
|
||||||
|
|
||||||
|
override fun serialize(context: IdeSerializationContext, value: T): ByteArray? {
|
||||||
|
return try {
|
||||||
|
ByteArrayOutputStream().use { byteArrayOutputStream ->
|
||||||
|
ObjectOutputStream(byteArrayOutputStream).use { oos -> oos.writeObject(value) }
|
||||||
|
byteArrayOutputStream.toByteArray()
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
context.logger.error("${ErrorMessages.SERIALIZATION_FAILURE} $value", t)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(context: IdeSerializationContext, data: ByteArray): T? {
|
||||||
|
return try {
|
||||||
|
ObjectInputStream(ByteArrayInputStream(data)).use { stream -> clazz.java.cast(stream.readObject()) }
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
context.logger.error("${ErrorMessages.DESERIALIZATION_FAILURE} ${clazz.java}", t)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ErrorMessages {
|
||||||
|
const val SERIALIZATION_FAILURE = "Failed to serialize"
|
||||||
|
const val DESERIALIZATION_FAILURE = "Failed to deserialize"
|
||||||
|
}
|
||||||
|
}
|
||||||
+150
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* 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.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
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.Overwrite
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.SourceSetConstraint
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.metadata.isNativeSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.getOrPut
|
||||||
|
import org.jetbrains.kotlin.tooling.core.Extras
|
||||||
|
|
||||||
|
interface IdeMultiplatformImport {
|
||||||
|
|
||||||
|
fun resolveDependencies(sourceSet: KotlinSourceSet): Set<IdeDependency>
|
||||||
|
|
||||||
|
fun <T : Any> serialize(key: Extras.Key<T>, value: T): ByteArray?
|
||||||
|
|
||||||
|
@ExternalKotlinTargetApi
|
||||||
|
fun registerDependencyResolver(
|
||||||
|
resolver: IdeDependencyResolver,
|
||||||
|
constraint: SourceSetConstraint,
|
||||||
|
phase: DependencyResolutionPhase,
|
||||||
|
level: DependencyResolutionLevel = Default,
|
||||||
|
)
|
||||||
|
|
||||||
|
@ExternalKotlinTargetApi
|
||||||
|
fun registerDependencyTransformer(
|
||||||
|
transformer: IdeDependencyTransformer,
|
||||||
|
constraint: SourceSetConstraint,
|
||||||
|
phase: DependencyTransformationPhase
|
||||||
|
)
|
||||||
|
|
||||||
|
@ExternalKotlinTargetApi
|
||||||
|
fun registerDependencyEffect(
|
||||||
|
effect: IdeDependencyEffect,
|
||||||
|
constraint: SourceSetConstraint
|
||||||
|
)
|
||||||
|
|
||||||
|
@ExternalKotlinTargetApi
|
||||||
|
fun registerExtrasSerializationExtension(
|
||||||
|
extension: IdeExtrasSerializationExtension
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any [IdeDependencyResolver] has to be registered for a given dependency resolution phase in which it participates
|
||||||
|
* The resolution phases will be executed in the order of their enum's ordinal.
|
||||||
|
*/
|
||||||
|
enum class DependencyResolutionPhase {
|
||||||
|
/**
|
||||||
|
* Generic phase intended to run before all other resolvers
|
||||||
|
*/
|
||||||
|
PreDependencyResolution,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolution phase intended to resolve project to project (source) dependencies
|
||||||
|
*/
|
||||||
|
SourceDependencyResolution,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolution phase intended to resolve binary dependencies (downloading and transforming from repositories)
|
||||||
|
*/
|
||||||
|
BinaryDependencyResolution,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic phase intended to run after all other resolvers.
|
||||||
|
*/
|
||||||
|
PostDependencyResolution
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any [IdeDependencyResolver] has to be registered specifying a certain resolution level.
|
||||||
|
* Generally, all resolvers registered in a given resolution level will work collaboratively, meaning the dependency resolution
|
||||||
|
* result is the aggregation of all resolvers running.
|
||||||
|
*
|
||||||
|
* However, only the resolvers in the highest resolution result will run e.g.
|
||||||
|
* If resolvers with level [Overwrite] are found, then only those will contribute to the dependency resolution.
|
||||||
|
* Otherwise, all [Default] resolvers will run.
|
||||||
|
*/
|
||||||
|
enum class DependencyResolutionLevel {
|
||||||
|
Default, Overwrite
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any [IdeDependencyResolver] has to be registered for a given transformation phase.
|
||||||
|
* The phases will be executed in the order of this enums ordinal.
|
||||||
|
*/
|
||||||
|
enum class DependencyTransformationPhase {
|
||||||
|
/**
|
||||||
|
* Generic dependency transformation phase, intended to run a transformation before all other transformers.
|
||||||
|
*/
|
||||||
|
PreDependencyTransformationPhase,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependency transformation phase that is free entirely free in its transformation type.
|
||||||
|
* Note: Adding dependencies to the resolution result might most likely better be modelled as [IdeDependencyResolver]
|
||||||
|
*/
|
||||||
|
FreeDependencyTransformationPhase,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special dependency transformation phase intended for filtering dependencies.
|
||||||
|
* This phase is guaranteed to run after the [FreeDependencyTransformationPhase] alongside other dependency filtering
|
||||||
|
* transformations. Adding filters here is the safest.
|
||||||
|
*/
|
||||||
|
DependencyFilteringPhase,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic dependency transformation phase, intended to run a transformation after all other transformers
|
||||||
|
*/
|
||||||
|
PostDependencyTransformationPhase
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for scoping [IdeDependencyResolver], [IdeDependencyResolver] and [IdeDependencyEffect]
|
||||||
|
*/
|
||||||
|
fun interface SourceSetConstraint {
|
||||||
|
operator fun invoke(sourceSet: KotlinSourceSet): Boolean
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val unconstrained = SourceSetConstraint { true }
|
||||||
|
val isNative = SourceSetConstraint { sourceSet -> isNativeSourceSet(sourceSet) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun instance(project: Project): IdeMultiplatformImport {
|
||||||
|
return project.extraProperties.getOrPut(IdeMultiplatformImport::class.java.name) {
|
||||||
|
IdeMultiplatformImport(project.multiplatformExtension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val Project.kotlinIdeMultiplatformImport: IdeMultiplatformImport get() = IdeMultiplatformImport.instance(project)
|
||||||
|
|
||||||
|
@ExternalKotlinTargetApi
|
||||||
|
fun IdeMultiplatformImport.registerExtrasSerializationExtension(
|
||||||
|
builder: IdeExtrasSerializationExtensionBuilder.() -> Unit
|
||||||
|
) {
|
||||||
|
registerExtrasSerializationExtension(IdeExtrasSerializationExtension(builder))
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.kpm.idea.kotlinDebugKey
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.IdeDependsOnDependencyResolver
|
||||||
|
|
||||||
|
fun IdeMultiplatformImport(extension: KotlinMultiplatformExtension): IdeMultiplatformImport {
|
||||||
|
return IdeMultiplatformImportImpl(extension).apply {
|
||||||
|
|
||||||
|
registerDependencyResolver(
|
||||||
|
resolver = IdeDependsOnDependencyResolver,
|
||||||
|
constraint = IdeMultiplatformImport.SourceSetConstraint.unconstrained,
|
||||||
|
phase = IdeMultiplatformImport.DependencyResolutionPhase.SourceDependencyResolution,
|
||||||
|
level = IdeMultiplatformImport.DependencyResolutionLevel.Default
|
||||||
|
)
|
||||||
|
|
||||||
|
registerExtrasSerializationExtension {
|
||||||
|
register(kotlinDebugKey, IdeExtrasSerializer.javaIoSerializable())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+132
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* 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.ExternalKotlinTargetApi
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.*
|
||||||
|
import org.jetbrains.kotlin.tooling.core.Extras
|
||||||
|
|
||||||
|
|
||||||
|
internal class IdeMultiplatformImportImpl(
|
||||||
|
private val extension: KotlinMultiplatformExtension
|
||||||
|
) : IdeMultiplatformImport {
|
||||||
|
|
||||||
|
override fun resolveDependencies(sourceSet: KotlinSourceSet): Set<IdeDependency> {
|
||||||
|
return createDependencyResolver().resolve(sourceSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> serialize(key: Extras.Key<T>, value: T): ByteArray? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class RegisteredDependencyResolver(
|
||||||
|
val resolver: IdeDependencyResolver,
|
||||||
|
val constraint: SourceSetConstraint,
|
||||||
|
val phase: DependencyResolutionPhase,
|
||||||
|
val level: DependencyResolutionLevel,
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class RegisteredDependencyTransformer(
|
||||||
|
val transformer: IdeDependencyTransformer,
|
||||||
|
val constraint: SourceSetConstraint,
|
||||||
|
val phase: DependencyTransformationPhase
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class RegisteredDependencyEffect(
|
||||||
|
val effect: IdeDependencyEffect,
|
||||||
|
val constraint: SourceSetConstraint,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val registeredDependencyResolvers = mutableListOf<RegisteredDependencyResolver>()
|
||||||
|
private val registeredDependencyTransformers = mutableListOf<RegisteredDependencyTransformer>()
|
||||||
|
private val registeredDependencyEffects = mutableListOf<RegisteredDependencyEffect>()
|
||||||
|
private val registeredExtrasSerializationExtensions = mutableListOf<IdeExtrasSerializationExtension>()
|
||||||
|
|
||||||
|
@ExternalKotlinTargetApi
|
||||||
|
override fun registerDependencyResolver(
|
||||||
|
resolver: IdeDependencyResolver,
|
||||||
|
constraint: SourceSetConstraint,
|
||||||
|
phase: DependencyResolutionPhase,
|
||||||
|
level: DependencyResolutionLevel
|
||||||
|
) {
|
||||||
|
registeredDependencyResolvers.add(
|
||||||
|
RegisteredDependencyResolver(resolver, constraint, phase, level)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExternalKotlinTargetApi
|
||||||
|
override fun registerDependencyTransformer(
|
||||||
|
transformer: IdeDependencyTransformer,
|
||||||
|
constraint: SourceSetConstraint,
|
||||||
|
phase: DependencyTransformationPhase
|
||||||
|
) {
|
||||||
|
registeredDependencyTransformers.add(
|
||||||
|
RegisteredDependencyTransformer(transformer, constraint, phase)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExternalKotlinTargetApi
|
||||||
|
override fun registerDependencyEffect(effect: IdeDependencyEffect, constraint: SourceSetConstraint) {
|
||||||
|
registeredDependencyEffects.add(
|
||||||
|
RegisteredDependencyEffect(effect, constraint)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExternalKotlinTargetApi
|
||||||
|
override fun registerExtrasSerializationExtension(extension: IdeExtrasSerializationExtension) {
|
||||||
|
registeredExtrasSerializationExtensions.add(extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDependencyResolver(): IdeDependencyResolver {
|
||||||
|
return IdeDependencyResolver(DependencyResolutionPhase.values().map { phase ->
|
||||||
|
createDependencyResolver(phase)
|
||||||
|
}).withTransformer(createDependencyTransformer())
|
||||||
|
.withEffect(createDependencyEffect())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDependencyResolver(phase: DependencyResolutionPhase) = IdeDependencyResolver resolve@{ sourceSet ->
|
||||||
|
val applicableResolvers = registeredDependencyResolvers
|
||||||
|
.filter { it.phase == phase }
|
||||||
|
.filter { it.constraint(sourceSet) }
|
||||||
|
.groupBy { it.level }
|
||||||
|
|
||||||
|
/* Find resolvers in the highest resolution level and only consider those */
|
||||||
|
DependencyResolutionLevel.values().reversed().forEach { level ->
|
||||||
|
val resolvers = applicableResolvers[level].orEmpty().map { it.resolver }
|
||||||
|
if (resolvers.isNotEmpty()) {
|
||||||
|
return@resolve IdeDependencyResolver(resolvers).resolve(sourceSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No resolvers found */
|
||||||
|
emptySet()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDependencyTransformer(): IdeDependencyTransformer {
|
||||||
|
return IdeDependencyTransformer(DependencyTransformationPhase.values().map { phase ->
|
||||||
|
createDependencyTransformer(phase)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDependencyTransformer(phase: DependencyTransformationPhase): IdeDependencyTransformer {
|
||||||
|
return IdeDependencyTransformer { sourceSet, dependencies ->
|
||||||
|
IdeDependencyTransformer(
|
||||||
|
registeredDependencyTransformers
|
||||||
|
.filter { it.phase == phase }
|
||||||
|
.filter { it.constraint(sourceSet) }
|
||||||
|
.map { it.transformer }
|
||||||
|
).transform(sourceSet, dependencies)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDependencyEffect(): IdeDependencyEffect = IdeDependencyEffect { sourceSet, dependencies ->
|
||||||
|
registeredDependencyEffects
|
||||||
|
.filter { it.constraint(sourceSet) }
|
||||||
|
.forEach { it.effect(sourceSet, dependencies) }
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
interface IdeSerializationContext {
|
||||||
|
val logger: IdeSerializationLogger
|
||||||
|
val extrasSerializationExtension: IdeExtrasSerializationExtension
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
interface IdeSerializationLogger {
|
||||||
|
enum class Severity {
|
||||||
|
WARNING,
|
||||||
|
ERROR,
|
||||||
|
}
|
||||||
|
|
||||||
|
fun report(severity: Severity, message: String, cause: Throwable? = null)
|
||||||
|
fun warn(message: String, cause: Throwable? = null) = report(Severity.WARNING, message, cause)
|
||||||
|
fun error(message: String, cause: Throwable? = null) = report(Severity.ERROR, message, cause)
|
||||||
|
|
||||||
|
object None : IdeSerializationLogger {
|
||||||
|
override fun report(severity: Severity, message: String, cause: Throwable?) = Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.gradle.plugin.KotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependency
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeSourceCoordinates
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeSourceDependency
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.currentBuildId
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
||||||
|
import org.jetbrains.kotlin.tooling.core.emptyExtras
|
||||||
|
|
||||||
|
internal object IdeDependsOnDependencyResolver : IdeDependencyResolver {
|
||||||
|
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeDependency> {
|
||||||
|
return sourceSet.internal.dependsOnClosure.map { dependsOnSourceSet ->
|
||||||
|
IdeSourceDependency(
|
||||||
|
type = IdeSourceDependency.Type.DependsOn,
|
||||||
|
coordinates = IdeSourceCoordinates(
|
||||||
|
buildId = dependsOnSourceSet.internal.project.currentBuildId().name,
|
||||||
|
projectPath = dependsOnSourceSet.internal.project.path,
|
||||||
|
projectName = dependsOnSourceSet.internal.project.name,
|
||||||
|
sourceSetName = dependsOnSourceSet.name
|
||||||
|
),
|
||||||
|
extras = emptyExtras()
|
||||||
|
)
|
||||||
|
}.toSet()
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -11,6 +11,7 @@ import org.gradle.api.Action
|
|||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.file.SourceDirectorySet
|
import org.gradle.api.file.SourceDirectorySet
|
||||||
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
|
||||||
|
import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
|
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
@@ -24,8 +25,9 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
const val METADATA_CONFIGURATION_NAME_SUFFIX = "DependenciesMetadata"
|
const val METADATA_CONFIGURATION_NAME_SUFFIX = "DependenciesMetadata"
|
||||||
|
|
||||||
|
@InternalKotlinGradlePluginApi
|
||||||
abstract class DefaultKotlinSourceSet @Inject constructor(
|
abstract class DefaultKotlinSourceSet @Inject constructor(
|
||||||
private val project: Project,
|
final override val project: Project,
|
||||||
val displayName: String
|
val displayName: String
|
||||||
) : AbstractKotlinSourceSet() {
|
) : AbstractKotlinSourceSet() {
|
||||||
|
|
||||||
|
|||||||
+2
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.plugin.sources
|
package org.jetbrains.kotlin.gradle.plugin.sources
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.utils.MutableObservableSet
|
import org.jetbrains.kotlin.gradle.utils.MutableObservableSet
|
||||||
@@ -16,6 +17,7 @@ internal val KotlinSourceSet.internal: InternalKotlinSourceSet
|
|||||||
)
|
)
|
||||||
|
|
||||||
internal interface InternalKotlinSourceSet : KotlinSourceSet {
|
internal interface InternalKotlinSourceSet : KotlinSourceSet {
|
||||||
|
val project: Project
|
||||||
override val dependsOn: ObservableSet<KotlinSourceSet>
|
override val dependsOn: ObservableSet<KotlinSourceSet>
|
||||||
val dependsOnClosure: ObservableSet<KotlinSourceSet>
|
val dependsOnClosure: ObservableSet<KotlinSourceSet>
|
||||||
val withDependsOnClosure: ObservableSet<KotlinSourceSet>
|
val withDependsOnClosure: ObservableSet<KotlinSourceSet>
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("FunctionName")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.ide
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.buildProjectWithMPP
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeSourceDependency
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.kotlinIdeMultiplatformImport
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
class IdeMultiplatformResolveDependsOnDependenciesTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - sample 0 - default dependsOn to commonMain and commonTest`() {
|
||||||
|
val project = buildProjectWithMPP()
|
||||||
|
val kotlin = project.multiplatformExtension
|
||||||
|
kotlin.jvm()
|
||||||
|
|
||||||
|
val commonMain = kotlin.sourceSets.getByName("commonMain")
|
||||||
|
val commonTest = kotlin.sourceSets.getByName("commonTest")
|
||||||
|
val jvmMain = kotlin.sourceSets.getByName("jvmMain")
|
||||||
|
val jvmTest = kotlin.sourceSets.getByName("jvmTest")
|
||||||
|
|
||||||
|
|
||||||
|
project.kotlinIdeMultiplatformImport.resolveDependencies(jvmMain)
|
||||||
|
.filterIsInstance<IdeSourceDependency>()
|
||||||
|
.assertMatches(dependsOnDependency(commonMain))
|
||||||
|
|
||||||
|
|
||||||
|
project.kotlinIdeMultiplatformImport.resolveDependencies(jvmTest)
|
||||||
|
.filterIsInstance<IdeSourceDependency>()
|
||||||
|
.assertMatches(dependsOnDependency(commonTest))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - sample 1 - custom dependsOn edge`() {
|
||||||
|
val project = buildProjectWithMPP()
|
||||||
|
val kotlin = project.multiplatformExtension
|
||||||
|
kotlin.jvm()
|
||||||
|
val commonMain = kotlin.sourceSets.getByName("commonMain")
|
||||||
|
val customMain = kotlin.sourceSets.create("customMain")
|
||||||
|
val jvmMain = kotlin.sourceSets.getByName("jvmMain")
|
||||||
|
|
||||||
|
jvmMain.dependsOn(customMain)
|
||||||
|
customMain.dependsOn(commonMain)
|
||||||
|
|
||||||
|
project.kotlinIdeMultiplatformImport.resolveDependencies(jvmMain)
|
||||||
|
.filterIsInstance<IdeSourceDependency>()
|
||||||
|
.assertMatches(
|
||||||
|
dependsOnDependency(commonMain),
|
||||||
|
dependsOnDependency(customMain)
|
||||||
|
)
|
||||||
|
|
||||||
|
project.kotlinIdeMultiplatformImport.resolveDependencies(customMain)
|
||||||
|
.filterIsInstance<IdeSourceDependency>()
|
||||||
|
.assertMatches(dependsOnDependency(commonMain))
|
||||||
|
}
|
||||||
|
}
|
||||||
+91
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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.ide
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependency
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeSourceDependency
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
||||||
|
import org.junit.jupiter.api.fail
|
||||||
|
|
||||||
|
fun buildIdeDependencyMatchers(notation: Any?): List<IdeDependencyMatcher> {
|
||||||
|
return when (notation) {
|
||||||
|
null -> return emptyList()
|
||||||
|
is IdeDependencyMatcher -> listOf(notation)
|
||||||
|
is Iterable<*> -> notation.flatMap { buildIdeDependencyMatchers(it) }
|
||||||
|
else -> error("Can't build ${IdeSourceDependencyMatcher::class.java.simpleName} from $notation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ideSourceDependency(type: IdeSourceDependency.Type, project: Project, sourceSetName: String): IdeDependencyMatcher {
|
||||||
|
return IdeSourceDependencyMatcher(type, project.path, sourceSetName)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dependsOnDependency(project: Project, sourceSetName: String) =
|
||||||
|
ideSourceDependency(IdeSourceDependency.Type.DependsOn, project, sourceSetName)
|
||||||
|
|
||||||
|
fun dependsOnDependency(sourceSet: KotlinSourceSet) =
|
||||||
|
dependsOnDependency(sourceSet.internal.project, sourceSet.name)
|
||||||
|
|
||||||
|
interface IdeDependencyMatcher {
|
||||||
|
val description: String
|
||||||
|
fun matches(dependency: IdeDependency): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IdeSourceDependencyMatcher(
|
||||||
|
val type: IdeSourceDependency.Type,
|
||||||
|
val projectPath: String,
|
||||||
|
val sourceSetName: String
|
||||||
|
) : IdeDependencyMatcher {
|
||||||
|
override val description: String =
|
||||||
|
"source($type)::$projectPath/$sourceSetName"
|
||||||
|
|
||||||
|
override fun matches(dependency: IdeDependency): Boolean {
|
||||||
|
if (dependency !is IdeSourceDependency) return false
|
||||||
|
return dependency.type == type &&
|
||||||
|
dependency.coordinates.projectPath == projectPath &&
|
||||||
|
dependency.coordinates.sourceSetName == sourceSetName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Iterable<IdeDependency>.assertMatches(vararg notation: Any?) {
|
||||||
|
val thisList = toList()
|
||||||
|
val matchers = notation.flatMap { buildIdeDependencyMatchers(it) }
|
||||||
|
|
||||||
|
val unexpectedDependencies = thisList.filter { dependency -> matchers.none { matcher -> matcher.matches(dependency) } }
|
||||||
|
val missingDependencies = matchers.filter { matcher -> thisList.none { dependency -> matcher.matches(dependency) } }
|
||||||
|
|
||||||
|
if (unexpectedDependencies.isEmpty() && missingDependencies.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fail(
|
||||||
|
buildString {
|
||||||
|
if (unexpectedDependencies.isNotEmpty()) {
|
||||||
|
appendLine()
|
||||||
|
appendLine("Unexpected dependency found:")
|
||||||
|
unexpectedDependencies.forEach { unexpectedDependency ->
|
||||||
|
appendLine("\"${unexpectedDependency}\",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingDependencies.isNotEmpty()) {
|
||||||
|
appendLine()
|
||||||
|
appendLine("Missing dependencies:")
|
||||||
|
missingDependencies.forEach { missingDependency ->
|
||||||
|
appendLine(missingDependency.description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendLine()
|
||||||
|
appendLine("Dependencies:")
|
||||||
|
thisList.forEach { dependency ->
|
||||||
|
appendLine("\"${dependency}\",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user