[Gradle] Remove ':kotlin-project-model' and ':kotlin-project-model-tests-generator'
KT-61463
This commit is contained in:
committed by
Space Team
parent
6d38a314cc
commit
02c2c76ffe
@@ -318,8 +318,6 @@
|
||||
/libraries/tools/kotlin-osgi-bundle/ "Kotlin Build Tools"
|
||||
/libraries/tools/kotlin-noarg/ "Kotlin Build Tools"
|
||||
/libraries/tools/kotlin-prepush-hook/ "Kotlin Build Infrastructure"
|
||||
/libraries/tools/kotlin-project-model/ "Kotlin Multiplatform"
|
||||
/libraries/tools/kotlin-project-model-tests-generator/ "Kotlin Multiplatform"
|
||||
/libraries/tools/kotlin-sam-with-receiver/ "Kotlin Build Tools"
|
||||
/libraries/tools/kotlin-script-util/ "Kotlin Compiler Core"
|
||||
/libraries/tools/kotlin-serialization/ "Kotlin Build Tools"
|
||||
|
||||
@@ -1442,3 +1442,11 @@ public final class org/jetbrains/kotlin/gradle/tasks/UsesKotlinJavaToolchain$Def
|
||||
public static fun getKotlinJavaToolchain (Lorg/jetbrains/kotlin/gradle/tasks/UsesKotlinJavaToolchain;)Lorg/jetbrains/kotlin/gradle/tasks/KotlinJavaToolchain;
|
||||
}
|
||||
|
||||
public abstract interface class org/jetbrains/kotlin/project/model/LanguageSettings {
|
||||
public abstract fun getApiVersion ()Ljava/lang/String;
|
||||
public abstract fun getEnabledLanguageFeatures ()Ljava/util/Set;
|
||||
public abstract fun getLanguageVersion ()Ljava/lang/String;
|
||||
public abstract fun getOptInAnnotationsInUse ()Ljava/util/Set;
|
||||
public abstract fun getProgressiveMode ()Z
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ dependencies {
|
||||
commonApi(platform(project(":kotlin-gradle-plugins-bom")))
|
||||
commonApi(project(":kotlin-gradle-plugin-annotations"))
|
||||
commonApi(project(":native:kotlin-native-utils"))
|
||||
commonApi(project(":kotlin-project-model"))
|
||||
commonApi(project(":kotlin-tooling-core"))
|
||||
|
||||
commonCompileOnly(project(":kotlin-gradle-compiler-types"))
|
||||
|
||||
+4
-2
@@ -1,8 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2023 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("PackageDirectoryMismatch")
|
||||
|
||||
package org.jetbrains.kotlin.project.model
|
||||
|
||||
interface LanguageSettings {
|
||||
@@ -11,4 +13,4 @@ interface LanguageSettings {
|
||||
val progressiveMode: Boolean
|
||||
val enabledLanguageFeatures: Set<String>
|
||||
val optInAnnotationsInUse: Set<String>
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,6 @@ dependencies {
|
||||
|
||||
testImplementation(project(":kotlin-gradle-plugin-model"))
|
||||
testImplementation(project(":kotlin-gradle-build-metrics"))
|
||||
testImplementation(project(":kotlin-project-model"))
|
||||
testImplementation(project(":kotlin-tooling-metadata"))
|
||||
testImplementation(kotlinGradlePluginTest)
|
||||
testImplementation(project(":kotlin-gradle-subplugin-example"))
|
||||
|
||||
-5
@@ -14,13 +14,9 @@ import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.process.ExecOperations
|
||||
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
|
||||
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
|
||||
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2NativeCompilerArguments
|
||||
import org.jetbrains.kotlin.compilerRunner.*
|
||||
import org.jetbrains.kotlin.gradle.dsl.*
|
||||
@@ -29,7 +25,6 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.Create
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||
import org.jetbrains.kotlin.gradle.report.GradleBuildMetricsReporter
|
||||
import org.jetbrains.kotlin.gradle.report.UsesBuildMetricsService
|
||||
import org.jetbrains.kotlin.gradle.targets.native.UsesKonanPropertiesBuildService
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.CompilerPluginData
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
id("java-test-fixtures")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation(kotlinStdlib())
|
||||
testApi(projectTests(":compiler:cli"))
|
||||
testApi(projectTests(":generators:test-generator"))
|
||||
testApi(testFixtures(project(":kotlin-project-model")))
|
||||
testApi(project(":kotlin-project-model"))
|
||||
testApi(projectTests(":kotlin-gradle-plugin-integration-tests"))
|
||||
testCompileOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
||||
testImplementation(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
||||
testImplementation(projectTests(":compiler:test-infrastructure-utils"))
|
||||
testImplementation(projectTests(":compiler:test-infrastructure"))
|
||||
testImplementation(projectTests(":compiler:tests-common-new"))
|
||||
testImplementation(projectTests(":js:js.tests"))
|
||||
testApiJUnit5()
|
||||
|
||||
if (Ide.IJ()) {
|
||||
testCompileOnly(jpsBuildTest())
|
||||
testApi(jpsBuildTest())
|
||||
}
|
||||
}
|
||||
|
||||
val generateKpmTests by generator("org.jetbrains.kotlin.kpm.GenerateKpmTestsKt") {
|
||||
}
|
||||
-14
@@ -1,14 +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.kpm
|
||||
|
||||
import org.jetbrains.kotlin.project.model.infra.generate.generateKpmTestCases
|
||||
|
||||
fun main() {
|
||||
generateKpmTestCases {
|
||||
// Add generated tests here
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
id("java-test-fixtures")
|
||||
}
|
||||
|
||||
publish()
|
||||
|
||||
standardPublicJars()
|
||||
|
||||
dependencies {
|
||||
implementation(kotlinStdlib())
|
||||
implementation(project(":kotlin-tooling-core"))
|
||||
testApiJUnit5(runner = true)
|
||||
testFixturesImplementation(project(":kotlin-tooling-core"))
|
||||
testFixturesImplementation(project(":core:util.runtime"))
|
||||
testFixturesImplementation(projectTests(":generators:test-generator"))
|
||||
testFixturesImplementation(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
||||
}
|
||||
|
||||
projectTest(jUnitMode = JUnitMode.JUnit5) {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
configureKotlinCompileTasksGradleCompatibility()
|
||||
|
||||
tasks.named<KotlinJvmCompile>("compileTestFixturesKotlin") {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs += listOf(
|
||||
"-XXLanguage:+AllowSealedInheritorsInDifferentFilesOfSamePackage",
|
||||
"-XXLanguage:+SealedInterfaces",
|
||||
"-Xjvm-default=all"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named<Jar>("jar") {
|
||||
manifestAttributes(manifest)
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
# Dependency Resolution in the Project Model
|
||||
|
||||
Dependency resolution is not a single task, it is a complex pipeline where the requested dependencies, considered an input, are transformed
|
||||
to mutliple possible kinds of results. To produce one kind of the results, another sort of dependency resolution result may be needed.
|
||||
Therefore, one may think of the process of resolving dependencies as of a pipeline that may produce results of different shapes when
|
||||
requested.
|
||||
|
||||
Some use cases only require a dependency resolution result of one kind (for example, 'get all other fragments that a given
|
||||
fragment can see'), and for them, it might be convenient to have a single facade returning just that kind of result.
|
||||
|
||||
This document describes all the granular tasks that one might put before dependency resolution implementations that work with the Kotlin
|
||||
Project Model, without attaching them to specific use cases.
|
||||
|
||||
## Internal dependency expansion
|
||||
|
||||
> We may remove this section if it turns out that we are going to use modules for test-on-production dependencies and the like
|
||||
|
||||
We allow declaring only some of the fragment dependencies between fragments inside a single module, and the fragment dependencies for the
|
||||
depending fragment's refines-children are inferred automatically. Also, declaring such a dependency implies that all refines-parents of the
|
||||
dependency fragment should be visible, too, as well as everything it sees via its own expanded module fragment dependencies (as well as
|
||||
transitive expansion results of the first-level expansion results, and so on).
|
||||
|
||||
The interface for this is `InternalDependencyExpansion` with a function that takes a `fragment` and returns all other fragments of the same
|
||||
module that the fragment should see. For ease of explanation and diagnostics, the results are grouped by the actual declared fragment
|
||||
dependency that led to each particular fragment having been added to the result.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
commonMain commonTestFixtures < - - - - -commonTest
|
||||
| | |
|
||||
jvmAndJsMain < - - - - jvmAndJsTestFixtures jvmAndJsTest
|
||||
| | |
|
||||
jvmMain jvmTestFixtures jvmTest
|
||||
```
|
||||
|
||||
Here, dashed arrows denote declared fragment dependencies. When we ask for fragments that `jvmAndJsTest` sees, we get:
|
||||
`commonTestFixtures` and `jvmAndJsTestFixtures` because `commonTest` depends on `commonTestFixtures, and then also `commonMain` and
|
||||
`jvmAndJsMain` because `jvmAndJsTestFixtures` depends on `jvmAndJsMain`.
|
||||
|
||||
Currently, the `DefaultInternalDependencyExpansion` implementation takes a function that matches variants of the module as if they take
|
||||
part in variant-aware dependency resolution. This function may actually perform matching of the variants or may rely on additional
|
||||
information (until attributes matching is implemented, it may search for explicit dependencies added between the variants).
|
||||
|
||||
## Dependency discovery
|
||||
|
||||
Given that dependency resolution may bring transtive dependencies, it is not enough to know what *declared dependencies* a fragment has to
|
||||
be able to properly inspect the resolution results. You With just those, you won't be able to ask
|
||||
'what fragments does this fragment sees from module `foo`?' if the module `foo` is only a transitive dependency.
|
||||
|
||||
This defines a task of *discovering module dependencies*, that is, finding which modules a fragment actually depends on, including the
|
||||
modules brought in as transitive dependencies.
|
||||
|
||||
With the granular modules of the Kotlin Project Model, this not a trivial task. A module may reference another module as a dependency onl in
|
||||
some of its fragments. Therefore, to decide whether a particular module `m` should be transitively included in the resolution results for
|
||||
one of our fragments `f` we have to first find out whether `f` sees any other fragment that declares a dependency on `m`. This is another
|
||||
dependency resolution task that is covered below.
|
||||
|
||||
## Module resolution
|
||||
|
||||
Given a module dependency, we should be able to build a Kotlin module for that dependency, as we will have to decompose the dependency on
|
||||
the whole module to dependencies on its granular parts. These granular parts are the variants and fragments. So it is reasonable to build
|
||||
a Kotlin module for a resolved dependency and reason about it in the same terms as we use for locally built modules.
|
||||
|
||||
This task in dependency resolution takes a module dependency and returns a Kotlin module. This may in fact be a Kotlin module that is built
|
||||
locally (for dependencies that point to it directly).
|
||||
|
||||
## Variant resolution
|
||||
|
||||
This is a simple task that is very much like Gradle's variant aware dependency resolution: given a variant (not just a fragment) of a
|
||||
consuming module and another dependency module, we should tell which of the dependency module's variants is the best match.
|
||||
|
||||
When we look at a consumer's variant, it is important to be able to pick a dependency's variant (and not as set of fragments), because
|
||||
variants produce final binaries, and for the consumer to produce a final binary from its variant, it needs a guarantee that the producer
|
||||
also could generate a complete binary (with all `expect`s covered by `actual`s). The confirmation of this is exactly the producer's variant.
|
||||
|
||||
## Fragment resolution
|
||||
|
||||
This is the task of dependency resolution that we ultimately need to find out which declarations a module fragment sees. Namely, given a
|
||||
module dependency, we have to determine which of the dependency's fragments the consumer's fragment may see.
|
||||
|
||||
To do that, we have to perform variant resolution for each of the variants that the depending variant participates in, and then intersect
|
||||
the refines-closures of the resolved variants, this will be the safe set of fragments whose declarations we may use because they are
|
||||
available in any variant that we will compile the fragment for.
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
// TODO: Add better Kotlin Variant Attributes management
|
||||
// Ideally we should respect the nature of Attributes and express values in form of Complete Lattice
|
||||
// Moreover we can add support for default and most used Value Types (eg. Enums)
|
||||
|
||||
open class KotlinAttributeKey(
|
||||
val uniqueName: String
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KotlinAttributeKey && uniqueName == other.uniqueName
|
||||
|
||||
override fun hashCode(): Int =
|
||||
uniqueName.hashCode()
|
||||
}
|
||||
|
||||
// TODO: Introduce ENUM
|
||||
object KotlinPlatformTypeAttribute : KotlinAttributeKey("org.jetbrains.kotlin.platform.type") {
|
||||
const val JVM = "jvm"
|
||||
const val ANDROID_JVM = "androidJvm"
|
||||
const val JS = "js"
|
||||
const val NATIVE = "native"
|
||||
}
|
||||
|
||||
object KotlinNativeTargetAttribute : KotlinAttributeKey("org.jetbrains.kotlin.native.target")
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.project.model
|
||||
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Adapts Kotlin Compiler Plugin for Multiplatform Kotlin Project Model
|
||||
* Build System uses this interface to identify applicable plugin artifacts and its options
|
||||
* before executing actual Kotlin Compilation
|
||||
*/
|
||||
interface KpmCompilerPlugin {
|
||||
|
||||
/**
|
||||
* Returns [PluginData] when applicable for [fragment] compilation
|
||||
* Returns [null] if not applicable
|
||||
*/
|
||||
fun forMetadataCompilation(fragment: KpmFragment): PluginData?
|
||||
|
||||
/**
|
||||
* Returns [PluginData] when applicable for [fragment] compilation
|
||||
* Returns [null] if not applicable
|
||||
*/
|
||||
fun forNativeMetadataCompilation(fragment: KpmFragment): PluginData?
|
||||
|
||||
/**
|
||||
* Returns [PluginData] when applicable for [variant] compilation
|
||||
* Returns [null] if not applicable
|
||||
*/
|
||||
fun forPlatformCompilation(variant: KpmVariant): PluginData?
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin data can be used for changing some compilation request
|
||||
*/
|
||||
data class PluginData(
|
||||
val pluginId: String,
|
||||
val artifact: ArtifactCoordinates,
|
||||
val options: List<PluginOption>
|
||||
) {
|
||||
// FIXME: (?) Is it common thing or gradle/maven centric?
|
||||
data class ArtifactCoordinates(
|
||||
val group: String,
|
||||
val artifact: String,
|
||||
val version: String? = null
|
||||
)
|
||||
}
|
||||
|
||||
sealed class PluginOption {
|
||||
abstract val key: String
|
||||
|
||||
/**
|
||||
* Indicates whether value of [PluginOption] should be stored for incremental build checks.
|
||||
* Value changes of non-transient [PluginOption] will invalidate incremental caches.
|
||||
*/
|
||||
abstract val isTransient: Boolean
|
||||
}
|
||||
|
||||
data class StringOption(
|
||||
override val key: String,
|
||||
val value: String,
|
||||
override val isTransient: Boolean = false
|
||||
) : PluginOption()
|
||||
|
||||
data class FilesOption(
|
||||
override val key: String,
|
||||
val files: List<File>,
|
||||
/**
|
||||
* Indicates whether FilesOption is used as input or output during compilation
|
||||
* false means input
|
||||
* true means output
|
||||
*/
|
||||
val isOutput: Boolean = false,
|
||||
override val isTransient: Boolean = false
|
||||
) : PluginOption()
|
||||
|
||||
// TODO: It should be part of "Compilation Process": KotlinModule.compilationRequestFor(METADATA | PLATFORM) -> CompilationRequest
|
||||
// But there is no such thing at the moment :)
|
||||
fun KpmFragment.metadataCompilationPluginData(): List<PluginData> =
|
||||
containingModule
|
||||
.plugins
|
||||
.mapNotNull { plugin -> plugin.forMetadataCompilation(this) }
|
||||
|
||||
fun KpmFragment.nativeMetadataCompilationPluginData(): List<PluginData> =
|
||||
containingModule
|
||||
.plugins
|
||||
.mapNotNull { plugin -> plugin.forNativeMetadataCompilation(this) }
|
||||
|
||||
fun KpmVariant.platformCompilationPluginData(): List<PluginData> =
|
||||
containingModule
|
||||
.plugins
|
||||
.mapNotNull { plugin -> plugin.forPlatformCompilation(this) }
|
||||
|
||||
/**
|
||||
* Represents trivial Compiler Plugin adapter for Kotlin Project Model
|
||||
* Where Compiler Plugin can have common and native artifacts
|
||||
*/
|
||||
abstract class BasicKpmCompilerPlugin : KpmCompilerPlugin {
|
||||
|
||||
abstract val pluginId: String
|
||||
|
||||
protected abstract fun commonPluginArtifact(): PluginData.ArtifactCoordinates?
|
||||
|
||||
protected abstract fun nativePluginArtifact(): PluginData.ArtifactCoordinates?
|
||||
|
||||
protected abstract val pluginOptions: List<PluginOption>
|
||||
|
||||
override fun forMetadataCompilation(fragment: KpmFragment) = pluginDataOrNull(commonPluginArtifact())
|
||||
|
||||
override fun forNativeMetadataCompilation(fragment: KpmFragment) = pluginDataOrNull(nativePluginArtifact())
|
||||
|
||||
override fun forPlatformCompilation(variant: KpmVariant) =
|
||||
when (variant.platform) {
|
||||
KotlinPlatformTypeAttribute.NATIVE -> nativePluginArtifact()
|
||||
else -> commonPluginArtifact()
|
||||
}.let(::pluginDataOrNull)
|
||||
|
||||
private fun pluginDataOrNull(artifact: PluginData.ArtifactCoordinates?) =
|
||||
if (artifact != null) PluginData(pluginId, artifact, pluginOptions)
|
||||
else null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +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.project.model
|
||||
|
||||
interface KpmDependencyGraphResolver {
|
||||
fun resolveDependencyGraph(requestingModule: KpmModule): KpmDependencyGraphResolution
|
||||
}
|
||||
|
||||
sealed class KpmDependencyGraphResolution(open val requestingModule: KpmModule) {
|
||||
class Unknown(requestingModule: KpmModule) : KpmDependencyGraphResolution(requestingModule)
|
||||
open class KpmDependencyGraph(
|
||||
requestingModule: KpmModule, open val root: KpmDependencyGraphNode
|
||||
) : KpmDependencyGraphResolution(requestingModule)
|
||||
}
|
||||
|
||||
// TODO: should this be a single graph for all dependency scopes as well, not just for all fragments?
|
||||
open class KpmDependencyGraphNode(
|
||||
open val module: KpmModule,
|
||||
open val dependenciesByFragment: Map<KpmFragment, Iterable<KpmDependencyGraphNode>>
|
||||
) {
|
||||
override fun toString(): String = "node ${module}"
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
|
||||
import org.jetbrains.kotlin.tooling.core.closure
|
||||
import org.jetbrains.kotlin.tooling.core.withClosure
|
||||
import java.io.File
|
||||
|
||||
interface KpmFragment {
|
||||
val containingModule: KpmModule
|
||||
|
||||
val fragmentName: String
|
||||
|
||||
val languageSettings: LanguageSettings?
|
||||
|
||||
// TODO: should this be source roots or source files?
|
||||
val kotlinSourceRoots: Iterable<File>
|
||||
|
||||
// TODO: scopes
|
||||
val declaredModuleDependencies: Iterable<KpmModuleDependency>
|
||||
|
||||
val declaredRefinesDependencies: Iterable<KpmFragment>
|
||||
|
||||
val refinesClosure: Set<KpmFragment>
|
||||
get() = this.closure { it.declaredRefinesDependencies }
|
||||
|
||||
val withRefinesClosure: Set<KpmFragment>
|
||||
get() = this.withClosure { it.declaredRefinesDependencies }
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
val KpmFragment.fragmentAttributeSets: Map<KotlinAttributeKey, Set<String>>
|
||||
get() = mutableMapOf<KotlinAttributeKey, MutableSet<String>>().apply {
|
||||
containingModule.variantsContainingFragment(this@fragmentAttributeSets).forEach { variant ->
|
||||
variant.variantAttributes.forEach { (attribute, value) ->
|
||||
getOrPut(attribute) { mutableSetOf() }.add(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val KpmVariant.platform get() = variantAttributes[KotlinPlatformTypeAttribute]
|
||||
val KpmVariant.nativeTarget get() = variantAttributes[KotlinNativeTargetAttribute]
|
||||
|
||||
open class KpmBasicFragment(
|
||||
override val containingModule: KpmModule,
|
||||
override val fragmentName: String,
|
||||
override val languageSettings: LanguageSettings? = null
|
||||
) : KpmFragment {
|
||||
|
||||
override val declaredRefinesDependencies: MutableSet<KpmBasicFragment> = mutableSetOf()
|
||||
|
||||
override val declaredModuleDependencies: MutableSet<KpmModuleDependency> = mutableSetOf()
|
||||
|
||||
override var kotlinSourceRoots: Iterable<File> = emptyList()
|
||||
|
||||
override fun toString(): String = "fragment $fragmentName"
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
|
||||
|
||||
interface KpmFragmentsResolver {
|
||||
fun getChosenFragments(
|
||||
requestingFragment: KpmFragment,
|
||||
dependencyModule: KpmModule
|
||||
): KpmFragmentResolution
|
||||
}
|
||||
|
||||
sealed class KpmFragmentResolution(val requestingFragment: KpmFragment, val dependencyModule: KpmModule) {
|
||||
class ChosenFragments(
|
||||
requestingFragment: KpmFragment,
|
||||
dependencyModule: KpmModule,
|
||||
val visibleFragments: Iterable<KpmFragment>,
|
||||
val variantResolutions: Iterable<KpmVariantResolution>
|
||||
) : KpmFragmentResolution(requestingFragment, dependencyModule)
|
||||
|
||||
class NotRequested(requestingFragment: KpmFragment, dependencyModule: KpmModule) :
|
||||
KpmFragmentResolution(requestingFragment, dependencyModule)
|
||||
|
||||
// TODO: think about restricting calls with the type system to avoid partial functions in resolvers?
|
||||
class Unknown(requestingFragment: KpmFragment, dependencyModule: KpmModule) :
|
||||
KpmFragmentResolution(requestingFragment, dependencyModule)
|
||||
}
|
||||
|
||||
class KpmDefaultFragmentsResolver(
|
||||
private val variantResolver: KpmModuleVariantResolver
|
||||
) : KpmFragmentsResolver {
|
||||
override fun getChosenFragments(
|
||||
requestingFragment: KpmFragment,
|
||||
dependencyModule: KpmModule
|
||||
): KpmFragmentResolution {
|
||||
val dependingModule = requestingFragment.containingModule
|
||||
val containingVariants = dependingModule.variantsContainingFragment(requestingFragment)
|
||||
|
||||
val chosenVariants = containingVariants.map { variantResolver.getChosenVariant(it, dependencyModule) }
|
||||
|
||||
// TODO: extend this to more cases with non-matching variants, revisit the behavior when no matching variant is found once we fix
|
||||
// local publishing of libraries with missing host-specific parts (it breaks transitive dependencies now)
|
||||
if (chosenVariants.none { it is KpmVariantResolution.KpmVariantMatch })
|
||||
return KpmFragmentResolution.NotRequested(requestingFragment, dependencyModule)
|
||||
|
||||
val chosenFragments = chosenVariants.map { variantResolution ->
|
||||
when (variantResolution) {
|
||||
is KpmVariantResolution.KpmVariantMatch -> variantResolution.chosenVariant.withRefinesClosure
|
||||
else -> emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
val result = if (chosenFragments.isEmpty())
|
||||
emptyList<KpmFragment>()
|
||||
else chosenFragments
|
||||
// Note this emulates the existing behavior that is lenient wrt to unresolved modules, but gives imprecise results. TODO revisit
|
||||
.filter { it.isNotEmpty() }
|
||||
.reduce { acc, it -> acc.intersect(it) }
|
||||
|
||||
return KpmFragmentResolution.ChosenFragments(requestingFragment, dependencyModule, result, chosenVariants)
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
// TODO Gradle allows having multiple capabilities in a published module, we need to figure out how we can include them in the module IDs
|
||||
|
||||
interface KpmModule {
|
||||
val moduleIdentifier: KpmModuleIdentifier
|
||||
|
||||
val fragments: Iterable<KpmFragment>
|
||||
|
||||
val variants: Iterable<KpmVariant>
|
||||
get() = fragments.filterIsInstance<KpmVariant>()
|
||||
|
||||
val plugins: Iterable<KpmCompilerPlugin>
|
||||
|
||||
// TODO: isSynthetic?
|
||||
}
|
||||
|
||||
open class KpmBasicModule(
|
||||
override val moduleIdentifier: KpmModuleIdentifier
|
||||
) : KpmModule {
|
||||
override val fragments = mutableListOf<KpmBasicFragment>()
|
||||
|
||||
override val plugins = mutableListOf<KpmCompilerPlugin>()
|
||||
|
||||
override fun toString(): String = "module $moduleIdentifier"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
data class KpmModuleDependency(val moduleIdentifier: KpmModuleIdentifier) {
|
||||
override fun toString(): String = "dependency $moduleIdentifier"
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO other kinds of dependencies: non-Kotlin: cinterop, CocoaPods, NPM dependencies?
|
||||
* support with different moduleIdentifiers? Introduce other kinds of dependencies than ModuleDependency?
|
||||
*/
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
// TODO ensure that resolvers are pluggable + custom dependency kinds (& result kinds?)
|
||||
// TODO think about state management: unresolved -> (known dependency graph?) ... -> completely resolved
|
||||
// it seems to be important to learn whether or not the model is final
|
||||
interface KpmModuleDependencyResolver {
|
||||
fun resolveDependency(requestingModule: KpmModule, moduleDependency: KpmModuleDependency): KpmModule?
|
||||
}
|
||||
@@ -1,33 +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.project.model
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
sealed class KpmModuleIdentifier(open val moduleClassifier: String?) : Serializable
|
||||
|
||||
data class KpmLocalModuleIdentifier(
|
||||
val buildId: String,
|
||||
val projectId: String,
|
||||
override val moduleClassifier: String?
|
||||
) : KpmModuleIdentifier(moduleClassifier) {
|
||||
companion object {
|
||||
private const val SINGLE_BUILD_ID = ":"
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
"project '$projectId'" +
|
||||
moduleClassifier?.let { " / $it" }.orEmpty() +
|
||||
buildId.takeIf { it != SINGLE_BUILD_ID }?.let { "(build '$it')" }.orEmpty()
|
||||
}
|
||||
|
||||
data class KpmMavenModuleIdentifier(
|
||||
val group: String,
|
||||
val name: String,
|
||||
override val moduleClassifier: String?
|
||||
) : KpmModuleIdentifier(moduleClassifier) {
|
||||
override fun toString(): String = "$group:$name" + moduleClassifier?.let { " / $it" }.orEmpty()
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
|
||||
interface KpmModuleVariantResolver {
|
||||
/**
|
||||
* Find the matching module variant of the [dependencyModule] for the consumer's [requestingVariant].
|
||||
*
|
||||
* This is a partial function. A particular resolver may not be capable to do variant matching for some [dependencyModule] or
|
||||
* some [requestingVariant] (to such an extent that a resolver may only know how to resolve a single [dependencyModule]'s variants, or
|
||||
* how to resolve module variants for a particular [requestingVariant]).
|
||||
* In this case it should return [KpmVariantResolution.Unknown], and the caller (which might be an aggregating [KpmModuleVariantResolver])
|
||||
* may consult other sources to get the variant match.
|
||||
*/
|
||||
fun getChosenVariant(requestingVariant: KpmVariant, dependencyModule: KpmModule): KpmVariantResolution
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the results of [dependencyModule]'s variant resolution for the [requestingVariant],
|
||||
* usually done by some [KpmModuleVariantResolver].
|
||||
*/
|
||||
sealed class KpmVariantResolution(
|
||||
val requestingVariant: KpmVariant,
|
||||
val dependencyModule: KpmModule
|
||||
) {
|
||||
companion object {
|
||||
fun fromMatchingVariants(
|
||||
requestingVariant: KpmVariant,
|
||||
dependencyModule: KpmModule,
|
||||
matchingVariants: Collection<KpmVariant>
|
||||
) = when (matchingVariants.size) {
|
||||
0 -> KpmNoVariantMatch(requestingVariant, dependencyModule)
|
||||
1 -> KpmVariantMatch(requestingVariant, dependencyModule, matchingVariants.single())
|
||||
else -> KpmAmbiguousVariants(requestingVariant, dependencyModule, matchingVariants)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String = when (this) {
|
||||
is KpmVariantMatch -> "match: ${chosenVariant.fragmentName}"
|
||||
is Unknown -> "unknown"
|
||||
is NotRequested -> "not requested"
|
||||
is KpmNoVariantMatch -> "no match"
|
||||
is KpmAmbiguousVariants -> "ambiguity: ${matchingVariants.joinToString { it.fragmentName }}"
|
||||
}
|
||||
|
||||
/**
|
||||
* The resolver decided that the [chosenVariant] is the best variant match.
|
||||
*/
|
||||
class KpmVariantMatch(
|
||||
requestingVariant: KpmVariant,
|
||||
dependencyModule: KpmModule,
|
||||
val chosenVariant: KpmVariant
|
||||
) : KpmVariantResolution(requestingVariant, dependencyModule)
|
||||
|
||||
// TODO: think about restricting calls with the type system to avoid partial functions in resolvers?
|
||||
class Unknown(requestingVariant: KpmVariant, dependencyModule: KpmModule) :
|
||||
KpmVariantResolution(requestingVariant, dependencyModule)
|
||||
|
||||
/**
|
||||
* Returned when the resolver detects that the [requestingVariant] does not depend on [dependencyModule] and therefore should not get
|
||||
* any variant of that module at all.
|
||||
*/
|
||||
class NotRequested(requestingVariant: KpmVariant, dependencyModule: KpmModule) :
|
||||
KpmVariantResolution(requestingVariant, dependencyModule)
|
||||
|
||||
/**
|
||||
* Returned when the resolver could not find any matching of the [dependencyModule] for the [requestingVariant], or variant matching was
|
||||
* done externally and the external system did not provide any details of the failure.
|
||||
*/
|
||||
class KpmNoVariantMatch(
|
||||
requestingVariant: KpmVariant,
|
||||
dependencyModule: KpmModule
|
||||
) : KpmVariantResolution(requestingVariant, dependencyModule)
|
||||
|
||||
/**
|
||||
* Returned when the resolver found multiple matching variants in the [dependencyModule] and failed to choose one of them as the
|
||||
* best match for the [requestingVariant].
|
||||
*/
|
||||
class KpmAmbiguousVariants(
|
||||
requestingVariant: KpmVariant,
|
||||
dependencyModule: KpmModule,
|
||||
val matchingVariants: Iterable<KpmVariant>
|
||||
) : KpmVariantResolution(requestingVariant, dependencyModule)
|
||||
}
|
||||
@@ -1,19 +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.project.model
|
||||
|
||||
interface KpmVariant : KpmFragment {
|
||||
val variantAttributes: Map<KotlinAttributeKey, String>
|
||||
}
|
||||
|
||||
class KpmBasicVariant(
|
||||
containingModule: KpmModule, fragmentName: String, languageSettings: LanguageSettings? = null
|
||||
) : KpmBasicFragment(
|
||||
containingModule, fragmentName, languageSettings
|
||||
), KpmVariant {
|
||||
override val variantAttributes: MutableMap<KotlinAttributeKey, String> = mutableMapOf()
|
||||
override fun toString(): String = "variant $fragmentName"
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model.utils
|
||||
|
||||
import org.jetbrains.kotlin.project.model.KpmModule
|
||||
import org.jetbrains.kotlin.project.model.KpmFragment
|
||||
import org.jetbrains.kotlin.project.model.KpmVariant
|
||||
import org.jetbrains.kotlin.tooling.core.closure
|
||||
|
||||
fun KpmModule.variantsContainingFragment(fragment: KpmFragment): Iterable<KpmVariant> =
|
||||
variants.filter { variant -> fragment in variant.withRefinesClosure }
|
||||
|
||||
fun KpmModule.findRefiningFragments(fragment: KpmFragment): Iterable<KpmFragment> {
|
||||
return fragment.closure { seedFragment ->
|
||||
fragments.filter { otherFragment -> seedFragment in otherFragment.declaredRefinesDependencies }
|
||||
}
|
||||
}
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Assumptions.assumeTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class DefaultModuleFragmentsResolverTest {
|
||||
val bundleFoo = simpleModuleBundle("foo")
|
||||
val bundleBar = simpleModuleBundle("bar")
|
||||
|
||||
val fragmentResolver = KpmDefaultFragmentsResolver(MatchVariantsByExactAttributes())
|
||||
|
||||
@Test
|
||||
fun testFragmentVisibility() {
|
||||
val moduleFooMain = bundleFoo.main
|
||||
val moduleBarMain = bundleBar.main
|
||||
|
||||
val expectedVisibleFragments = mapOf(
|
||||
"common" to setOf("common"),
|
||||
"jvmAndJs" to setOf("common", "jvmAndJs"),
|
||||
"jsAndLinux" to setOf("common", "jsAndLinux"),
|
||||
"jvm" to setOf("common", "jvmAndJs", "jvm"),
|
||||
"js" to setOf("common", "jvmAndJs", "jsAndLinux", "js"),
|
||||
"linux" to setOf("common", "jsAndLinux", "linux")
|
||||
)
|
||||
|
||||
moduleBarMain.fragments.forEach { consumingFragment ->
|
||||
val result = fragmentResolver.getChosenFragments(consumingFragment, moduleFooMain)
|
||||
assertTrue(result is KpmFragmentResolution.ChosenFragments)
|
||||
val expected = expectedVisibleFragments.getValue(consumingFragment.fragmentName)
|
||||
assertEquals(expected, (result as KpmFragmentResolution.ChosenFragments).visibleFragments.map { it.fragmentName }.toSet())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testVisibilityWithMismatchedVariant() {
|
||||
// TODO this behavior replicates 1.3.x MPP where a mismatched variant gets ignored and only matched variants are intersected.
|
||||
// This helps with non-published local native targets.
|
||||
// Consider making it more strict when we have a solution to the original problem.
|
||||
val dependingModule = simpleModuleBundle("baz").main.apply {
|
||||
variant("linux").variantAttributes.replace(KotlinNativeTargetAttribute, "notLinux")
|
||||
}
|
||||
val moduleFooMain = bundleFoo.main
|
||||
val variantResolution = MatchVariantsByExactAttributes().getChosenVariant(dependingModule.variant("linux"), moduleFooMain)
|
||||
assumeTrue(variantResolution is KpmVariantResolution.KpmNoVariantMatch)
|
||||
|
||||
val (commonMainResult, jsAndLinuxResult) = listOf("common", "jsAndLinux").map {
|
||||
val chosenFragments = fragmentResolver.getChosenFragments(dependingModule.fragment(it), moduleFooMain)
|
||||
assertTrue(chosenFragments is KpmFragmentResolution.ChosenFragments)
|
||||
(chosenFragments as KpmFragmentResolution.ChosenFragments).visibleFragments.map { it.fragmentName }.toSet()
|
||||
}
|
||||
|
||||
assertEquals(setOf("common", "jvmAndJs"), commonMainResult)
|
||||
assertEquals(setOf("common", "jvmAndJs", "jsAndLinux", "js"), jsAndLinuxResult)
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
class MatchVariantsByExactAttributes : KpmModuleVariantResolver {
|
||||
override fun getChosenVariant(requestingVariant: KpmVariant, dependencyModule: KpmModule): KpmVariantResolution {
|
||||
val candidates = dependencyModule.variants
|
||||
return candidates.filter { candidate ->
|
||||
candidate.variantAttributes.all { (attributeKey, candidateValue) ->
|
||||
attributeKey !in requestingVariant.variantAttributes.keys ||
|
||||
candidateValue == requestingVariant.variantAttributes.getValue(attributeKey)
|
||||
}
|
||||
}.let { KpmVariantResolution.fromMatchingVariants(requestingVariant, dependencyModule, it) }
|
||||
}
|
||||
}
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.project.model
|
||||
|
||||
fun module(name: String, classifier: String? = null) = KpmBasicModule(KpmLocalModuleIdentifier("current", name, classifier))
|
||||
|
||||
fun KpmBasicModule.fragment(vararg nameParts: String): KpmBasicFragment =
|
||||
fragment(nameParts.drop(1).joinToString("", nameParts.first()) { it.capitalize() })
|
||||
|
||||
fun KpmBasicModule.fragment(name: String): KpmBasicFragment =
|
||||
fragments.firstOrNull { it.fragmentName == name } ?: KpmBasicFragment(this, name).also { fragments.add(it) }
|
||||
|
||||
fun KpmBasicModule.variant(vararg nameParts: String): KpmBasicVariant =
|
||||
variant(nameParts.drop(1).joinToString("", nameParts.first()) { it.capitalize() })
|
||||
|
||||
fun KpmBasicModule.variant(name: String): KpmBasicVariant =
|
||||
fragments.firstOrNull { it.fragmentName == name }
|
||||
?.let { it as? KpmBasicVariant ?: error("$name is not a variant") }
|
||||
?: KpmBasicVariant(this, name).also { fragments.add(it) }
|
||||
|
||||
fun KpmModuleIdentifier.equalsWithoutClassifier(other: KpmModuleIdentifier) = when (this) {
|
||||
is KpmLocalModuleIdentifier -> other is KpmLocalModuleIdentifier &&
|
||||
KpmLocalModuleIdentifier(buildId, projectId, null) == KpmLocalModuleIdentifier(other.buildId, other.projectId, null)
|
||||
is KpmMavenModuleIdentifier -> other is KpmMavenModuleIdentifier &&
|
||||
KpmMavenModuleIdentifier(group, name, null) == KpmMavenModuleIdentifier(other.group, other.name, null)
|
||||
else -> error("can't check equality yet")
|
||||
}
|
||||
|
||||
fun KpmBasicFragment.depends(module: KpmBasicModule) {
|
||||
this.declaredModuleDependencies += KpmModuleDependency(module.moduleIdentifier)
|
||||
}
|
||||
|
||||
fun KpmBasicFragment.refinedBy(fragment: KpmBasicFragment) {
|
||||
fragment.refines(this)
|
||||
}
|
||||
|
||||
fun KpmBasicFragment.refines(fragment: KpmBasicFragment) {
|
||||
require(fragment.containingModule == containingModule)
|
||||
declaredRefinesDependencies.add(fragment)
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
internal data class ModuleBundle(val modules: List<KpmBasicModule>) {
|
||||
val main: KpmBasicModule
|
||||
get() = modules.single { it.moduleIdentifier.moduleClassifier == null }
|
||||
|
||||
operator fun get(modulePurpose: String): KpmBasicModule = when (modulePurpose) {
|
||||
"main" -> main
|
||||
else -> modules.single { it.moduleIdentifier.moduleClassifier == modulePurpose }
|
||||
}
|
||||
}
|
||||
|
||||
internal fun simpleModuleBundle(name: String): ModuleBundle {
|
||||
fun createModule(purpose: String): KpmBasicModule =
|
||||
module(name, purpose.takeIf { it != "main" }).apply {
|
||||
val common = fragment("common")
|
||||
|
||||
val (jvm, js, linux) = listOf("jvm", "js", "linux").map { platform ->
|
||||
variant(platform).apply {
|
||||
variantAttributes[KotlinPlatformTypeAttribute] = when (platform) {
|
||||
"jvm" -> KotlinPlatformTypeAttribute.JVM
|
||||
"js" -> KotlinPlatformTypeAttribute.JS
|
||||
else -> {
|
||||
variantAttributes[KotlinNativeTargetAttribute] = platform
|
||||
KotlinPlatformTypeAttribute.NATIVE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment("jvmAndJs").apply {
|
||||
refines(common)
|
||||
refinedBy(jvm)
|
||||
refinedBy(js)
|
||||
}
|
||||
fragment("jsAndLinux").apply {
|
||||
refines(common)
|
||||
refinedBy(js)
|
||||
refinedBy(linux)
|
||||
}
|
||||
}
|
||||
|
||||
val main = createModule("main")
|
||||
val test = createModule("test")
|
||||
|
||||
test.fragment("common").depends(main)
|
||||
|
||||
return ModuleBundle(listOf(main, test))
|
||||
}
|
||||
-56
@@ -1,56 +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.project.model.infra
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class KpmCoreCasesRenderingTests : KpmCoreCasesTestRunner {
|
||||
@Test
|
||||
override fun testSimpleProjectToProject(case: KpmTestCase) {
|
||||
case.expectRenderedDsl(
|
||||
"""
|
||||
val SimpleProjectToProject = describeCase("SimpleProjectToProject") {
|
||||
project("a") {
|
||||
module("main") {
|
||||
jvm()
|
||||
macosX64()
|
||||
|
||||
common depends project("b")
|
||||
}
|
||||
}
|
||||
|
||||
project("b") {
|
||||
module("main") {
|
||||
jvm()
|
||||
macosX64()
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
override fun testSimpleTwoLevel(case: KpmTestCase) {
|
||||
case.expectRenderedDsl(
|
||||
"""
|
||||
val SimpleTwoLevel = describeCase("SimpleTwoLevel") {
|
||||
project("p") {
|
||||
module("main") {
|
||||
jvm()
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
private fun KpmTestCase.expectRenderedDsl(@Language("kotlin") expected: String) {
|
||||
Assertions.assertEquals(expected.trim(), this.renderDeclarationDsl().trim())
|
||||
}
|
||||
}
|
||||
-78
@@ -1,78 +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.project.model.coreCases
|
||||
|
||||
import org.jetbrains.kotlin.project.model.infra.KpmTestCase
|
||||
|
||||
/**
|
||||
* A representation of a Core Test Case.
|
||||
*
|
||||
* # Main idea:
|
||||
* - provides unified format for declaring project structure of core cases
|
||||
* - sync tested core cases across all subsystems
|
||||
*
|
||||
* # How it works:
|
||||
* - Core cases are defined inside [org.jetbrains.kotlin.project.model.coreCases]
|
||||
* (see "Conventions" below for exact format to follow) with the help of a DSL in
|
||||
* [org.jetbrains.kotlin.project.model.testDsl] package
|
||||
*
|
||||
* - Inherit [org.jetbrains.kotlin.project.model.infra.KpmCoreCasesTestRunner] in your
|
||||
* test runner. It will:
|
||||
* a) ensure that all core cases are covered and warn you when new one is added
|
||||
* b) inject core cases instances for you automatically
|
||||
*
|
||||
* - You can also use [org.jetbrains.kotlin.kpm.GenerateKpmTests]
|
||||
* if you don't need custom per-test-method assertions; it will generate test
|
||||
* cases which just call `doTest` on a passed [KpmTestCaseDescriptor] in a manner, similar
|
||||
* to other `*TestsGenerated`-runners
|
||||
*
|
||||
* # Conventions
|
||||
* 1. All Core Cases should inherit [KpmTestCaseDescriptor] marker
|
||||
* 2. All Core cases must reside in the [org.jetbrains.kotlin.project.model.coreCases]-package
|
||||
* 3. Each Core Case should be declared in a separate .kt-file, with the name equal
|
||||
* to the name of the case itself (`MyTestCase` -> `MyTestCase.kt`)
|
||||
* 4. Test Runner-class should consist of methods, which are named in the following
|
||||
* pattern: `test$caseName`
|
||||
* 5. (Optional) Test methods can declare a parameter of a [KpmTestCase]-type. Testing
|
||||
* infrastructure will inject an instance of corresponding [KpmTestCase]
|
||||
* (correspondence is determined based on test method naming convention from pt. 4)
|
||||
*
|
||||
* # Custom data, assertions, etc.
|
||||
* It is an explicit non-goal of this infrastructure to provide a DSL capable of
|
||||
* expressing assertions needed by an arbitrary subsystem. Instead, two extensibility
|
||||
* mechanisms are provided:
|
||||
* - `extras`, as in [KpmTestCase.extras]: essentially a way to attach custom userdata
|
||||
* to a given entity
|
||||
* - if needed, one can declare a new Core Case based on the previous one by calling
|
||||
* `describeCase` from "super-case" and then adding additional configuration
|
||||
*/
|
||||
sealed interface KpmTestCaseDescriptor {
|
||||
val name: String
|
||||
get() = this::class.simpleName ?: error("Can't get simpleName of a KpmTestCaseDescriptor ${this::class}. Is it an anonymous class?")
|
||||
|
||||
fun KpmTestCase.describeCase()
|
||||
|
||||
companion object {
|
||||
val allCaseDescriptorsByNames: Map<String, KpmTestCaseDescriptor> by lazy {
|
||||
doGetAllCases()
|
||||
}
|
||||
|
||||
val allCasesNames: Set<String>
|
||||
get() = allCaseDescriptorsByNames.keys
|
||||
|
||||
private fun doGetAllCases(): Map<String, KpmTestCaseDescriptor> = KpmTestCaseDescriptor::class.sealedSubclasses
|
||||
.map {
|
||||
requireNotNull(it.objectInstance) {
|
||||
"Can't get object instance for $it. Check that it is declared as an `object` "
|
||||
}
|
||||
}
|
||||
.associateBy { it.name }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun KpmTestCaseDescriptor.instantiateCase(): KpmTestCase = KpmTestCase(name).apply { describeCase() }
|
||||
|
||||
-23
@@ -1,23 +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.project.model.coreCases
|
||||
|
||||
import org.jetbrains.kotlin.project.model.infra.KpmTestCase
|
||||
import org.jetbrains.kotlin.project.model.testDsl.*
|
||||
|
||||
object SimpleProjectToProject : KpmTestCaseDescriptor {
|
||||
override fun KpmTestCase.describeCase() {
|
||||
allModules {
|
||||
jvm()
|
||||
macosX64()
|
||||
}
|
||||
|
||||
val a = project("a")
|
||||
val b = project("b")
|
||||
|
||||
a.depends(b)
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +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.project.model.coreCases
|
||||
|
||||
import org.jetbrains.kotlin.project.model.infra.KpmTestCase
|
||||
import org.jetbrains.kotlin.project.model.testDsl.*
|
||||
|
||||
object SimpleTwoLevel : KpmTestCaseDescriptor {
|
||||
override fun KpmTestCase.describeCase() {
|
||||
project("p") {
|
||||
allModules {
|
||||
jvm()
|
||||
macosX64()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +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.project.model.infra
|
||||
|
||||
import org.jetbrains.kotlin.project.model.coreCases.KpmTestCaseDescriptor
|
||||
import org.jetbrains.kotlin.project.model.coreCases.instantiateCase
|
||||
import org.junit.jupiter.api.extension.*
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class KpmCoreCasesJunitParameterResolver : ParameterResolver {
|
||||
override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean =
|
||||
parameterContext.parameter.type == KpmTestCaseDescriptor::class.java
|
||||
|
||||
override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
|
||||
require(parameterContext.parameter.type == KpmTestCaseDescriptor::class.java)
|
||||
val kpmCaseName = extensionContext.requiredTestMethod.kpmCaseName
|
||||
val caseDescriptor = KpmTestCaseDescriptor.allCaseDescriptorsByNames[kpmCaseName]
|
||||
requireNotNull(caseDescriptor) {
|
||||
"Can't find KpmCoreCase for name $kpmCaseName while " +
|
||||
"\n injecting parameter ${parameterContext.parameter} into \n" +
|
||||
"${extensionContext.requiredTestMethod}"
|
||||
}
|
||||
return caseDescriptor.instantiateCase()
|
||||
}
|
||||
}
|
||||
|
||||
private val Method.kpmCaseName: String
|
||||
get() {
|
||||
val testCaseName = this.name.substringAfter("test")
|
||||
require(testCaseName in KpmTestCaseDescriptor.allCasesNames) {
|
||||
"Can't find matching core case for name ${testCaseName}.\n" +
|
||||
"Please check that the test method follow pattern 'test\$caseName', \n" +
|
||||
"where '\$caseName' is a name as declared in 'o.j.k.project.model.coreCases'-package\n" +
|
||||
"\n" +
|
||||
"Known cases:\n" +
|
||||
"${KpmTestCaseDescriptor.allCasesNames}"
|
||||
}
|
||||
|
||||
return testCaseName
|
||||
}
|
||||
-67
@@ -1,67 +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.project.model.infra
|
||||
|
||||
import org.jetbrains.kotlin.project.model.coreCases.KpmTestCaseDescriptor
|
||||
import org.jetbrains.kotlin.project.model.infra.generate.generateTestMethodsTemplateForCases
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
|
||||
/**
|
||||
* Base class for testing KPM Core cases
|
||||
*
|
||||
* All core cases are listed here as abstract tests and will be required,
|
||||
* to be overridden introducing a compile-time check that as soon as new
|
||||
* case is added, it will be covered in all inheritors.
|
||||
*
|
||||
* For situation when a new Core Case is added, but is mistakenly not added
|
||||
* to this interface, there's a [checkAllCoreCasesCovered], which will enforce
|
||||
* that all Core Cases have a respective method in this interface
|
||||
*
|
||||
* Additionally, this interface uses [KpmCoreCasesJunitParameterResolver], which
|
||||
* will inject a corresponding [KpmTestCaseDescriptor] into a test-method based on the
|
||||
* method's name
|
||||
*/
|
||||
@ExtendWith(KpmCoreCasesJunitParameterResolver::class)
|
||||
interface KpmCoreCasesTestRunner {
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testSimpleProjectToProject(case: KpmTestCase)
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testSimpleTwoLevel(case: KpmTestCase)
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun checkAllCoreCasesCovered() {
|
||||
val testRunnerClass = this::class.java
|
||||
|
||||
val testCasesNames = testRunnerClass.methods.asSequence()
|
||||
.map { it.name }
|
||||
.filter { it.startsWith("test") }
|
||||
.map { it.substringAfter("test") }
|
||||
.toSet()
|
||||
|
||||
val uncoveredCases = KpmTestCaseDescriptor.allCasesNames - testCasesNames
|
||||
if (uncoveredCases.isNotEmpty()) {
|
||||
Assertions.fail<Nothing>(
|
||||
"""
|
||||
Test runner '${testRunnerClass.canonicalName}'
|
||||
has some KPM Core Test Cases uncovered:
|
||||
|
||||
${uncoveredCases.joinToString()}
|
||||
""".trimIndent() + "\n\n" + fixSuggestion(uncoveredCases)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fixSuggestion(missingCases: Set<String>): String =
|
||||
"Please re-run \"Generate KPM Tests\"-task to generate missing methods,\n" +
|
||||
"or insert the following scaffold if the test runner uses custom assertions:\n\n" +
|
||||
generateTestMethodsTemplateForCases(missingCases)
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.project.model.infra
|
||||
|
||||
import org.jetbrains.kotlin.project.model.*
|
||||
import org.jetbrains.kotlin.project.model.testDsl.*
|
||||
import org.jetbrains.kotlin.project.model.utils.ObservableIndexedCollection
|
||||
import org.jetbrains.kotlin.tooling.core.MutableExtras
|
||||
import org.jetbrains.kotlin.tooling.core.mutableExtrasOf
|
||||
import java.io.File
|
||||
|
||||
interface KpmTestEntity {
|
||||
val name: String
|
||||
}
|
||||
|
||||
class KpmTestCase(
|
||||
override val name: String,
|
||||
) : KpmTestEntity {
|
||||
val projects: ObservableIndexedCollection<TestKpmModuleContainer> = ObservableIndexedCollection()
|
||||
val extras: MutableExtras = mutableExtrasOf()
|
||||
|
||||
override fun toString(): String = "Case $name"
|
||||
}
|
||||
|
||||
class TestKpmModuleContainer(
|
||||
val containingCase: KpmTestCase,
|
||||
override val name: String,
|
||||
) : KpmTestEntity {
|
||||
val modules: ObservableIndexedCollection<TestKpmModule> = ObservableIndexedCollection()
|
||||
val extras: MutableExtras = mutableExtrasOf()
|
||||
|
||||
fun applyDefaults() {
|
||||
module("main")
|
||||
}
|
||||
|
||||
override fun toString(): String = ":$name"
|
||||
}
|
||||
|
||||
class TestKpmModule(
|
||||
val containingProject: TestKpmModuleContainer,
|
||||
override val moduleIdentifier: KpmModuleIdentifier,
|
||||
) : KpmTestEntity, KpmModule {
|
||||
override val fragments: ObservableIndexedCollection<TestKpmFragment> = ObservableIndexedCollection()
|
||||
override val plugins: MutableSet<KpmCompilerPlugin> = mutableSetOf()
|
||||
val extras: MutableExtras = mutableExtrasOf()
|
||||
|
||||
override val name: String
|
||||
get() = moduleIdentifier.moduleClassifier ?: "main"
|
||||
|
||||
fun applyDefaults() {
|
||||
fragment("common")
|
||||
}
|
||||
}
|
||||
|
||||
open class TestKpmFragment(
|
||||
override val containingModule: TestKpmModule,
|
||||
override val fragmentName: String,
|
||||
) : KpmTestEntity, KpmFragment {
|
||||
override var languageSettings: LanguageSettings? = null
|
||||
val extras: MutableExtras = mutableExtrasOf()
|
||||
override val kotlinSourceRoots: MutableList<File> = mutableListOf()
|
||||
override val declaredModuleDependencies: MutableList<KpmModuleDependency> = mutableListOf()
|
||||
override val declaredRefinesDependencies: MutableList<TestKpmFragment> = mutableListOf()
|
||||
override val name: String get() = fragmentName
|
||||
|
||||
fun applyDefaults() {
|
||||
refines(containingModule.common)
|
||||
}
|
||||
}
|
||||
|
||||
class TestKpmVariant(
|
||||
containingModule: TestKpmModule,
|
||||
fragmentName: String,
|
||||
) : TestKpmFragment(containingModule, fragmentName), KpmTestEntity, KpmVariant {
|
||||
override val variantAttributes: MutableMap<KotlinAttributeKey, String> = mutableMapOf()
|
||||
}
|
||||
-25
@@ -1,25 +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.project.model.infra.generate
|
||||
|
||||
import org.jetbrains.kotlin.generators.MethodGenerator
|
||||
import org.jetbrains.kotlin.generators.model.MethodModel
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
object KpmCoreCaseTestMethodGenerator : MethodGenerator<KpmCoreCaseTestMethodModel>() {
|
||||
override val kind: MethodModel.Kind
|
||||
get() = KpmCoreCaseTestMethodModel.Kind
|
||||
|
||||
override fun generateSignature(method: KpmCoreCaseTestMethodModel, p: Printer) {
|
||||
p.print("public void test${method.name}(KpmTestCase kpmCase) throws Exception")
|
||||
}
|
||||
|
||||
override fun generateBody(method: KpmCoreCaseTestMethodModel, p: Printer) {
|
||||
val filePath = KtTestUtil.getFilePath(method.pathToTestCase)
|
||||
p.println("runTest(SourcesKt.addSourcesFromCanonicalFileStructure(kpmCase, new File(\"$filePath\")));")
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +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.project.model.infra.generate
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.generators.model.MethodModel
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil
|
||||
import java.io.File
|
||||
|
||||
class KpmCoreCaseTestMethodModel(
|
||||
override val name: String, // equals to name of corresponding KpmCoreCase
|
||||
internal val pathToTestSourcesRootDir: File,
|
||||
internal val pathToTestCase: File,
|
||||
) : MethodModel {
|
||||
object Kind : MethodModel.Kind()
|
||||
|
||||
override val dataString: String
|
||||
get() {
|
||||
val path = FileUtil.getRelativePath(pathToTestSourcesRootDir, pathToTestCase)!!
|
||||
return KtTestUtil.getFilePath(File(path))
|
||||
}
|
||||
override val tags: List<String>
|
||||
get() = emptyList()
|
||||
|
||||
override val kind: MethodModel.Kind
|
||||
get() = Kind
|
||||
}
|
||||
-95
@@ -1,95 +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.project.model.infra.generate
|
||||
|
||||
import org.jetbrains.kotlin.generators.model.AnnotationModel
|
||||
import org.jetbrains.kotlin.generators.model.MethodModel
|
||||
import org.jetbrains.kotlin.generators.model.TestClassModel
|
||||
import org.jetbrains.kotlin.project.model.coreCases.KpmTestCaseDescriptor
|
||||
import org.jetbrains.kotlin.project.model.infra.KpmTestCase
|
||||
import org.jetbrains.kotlin.project.model.infra.generateTemplateCanonicalFileStructure
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil
|
||||
import java.io.File
|
||||
|
||||
class KpmCoreCasesTestClassModel(
|
||||
// Root of testdata folder, inside it expected to find one folder per testcase
|
||||
// E.g. [additionalTestDataRoot] = "foo/bar", and we have KpmCoreCases "A" and "B"
|
||||
// Then folders "foo/bar/A" and "foo/bar/B" expected to exist and contain sources
|
||||
// for cases A, B. If they do not exist, they will be auto-generated with template
|
||||
// sources.
|
||||
private val additionalTestDataRoot: File,
|
||||
) : TestClassModel() {
|
||||
// Metadata-annotations enable IDE support for tests, like "Navigate to test data" action
|
||||
override val dataString: String // Will be used in @TestMetadata, needs to be path to folder with test data
|
||||
get() = KtTestUtil.getFilePath(additionalTestDataRoot)
|
||||
|
||||
override val dataPathRoot: String? // Will be used in @com.intellij.testFramework.TestDataPath
|
||||
get() = null // $PROJECT_ROOT will be used instead
|
||||
|
||||
override val name: String
|
||||
get() = error("Unused by infra, shouldn't be called")
|
||||
|
||||
override val tags: List<String>
|
||||
get() = emptyList()
|
||||
|
||||
override val innerTestClasses: Collection<TestClassModel>
|
||||
get() = emptyList()
|
||||
|
||||
override val methods: Collection<MethodModel> by lazy {
|
||||
doCollectMethods()
|
||||
}
|
||||
|
||||
override val isEmpty: Boolean
|
||||
get() = methods.isEmpty()
|
||||
|
||||
override val imports: Set<Class<*>>
|
||||
get() = super.imports + setOf(
|
||||
KpmTestCase::class.java,
|
||||
this::class.java.classLoader.loadClass("org.jetbrains.kotlin.project.model.infra.SourcesKt") // file-facade :(
|
||||
)
|
||||
|
||||
override val annotations: Collection<AnnotationModel>
|
||||
get() = emptyList() // Don't need to annotate with `@ExtendWith`, because we inherit [KpmCoreCasesTestRunner]
|
||||
|
||||
private fun doCollectMethods(): Collection<MethodModel> {
|
||||
val allCoreCasesNames: Set<String> = KpmTestCaseDescriptor.allCasesNames
|
||||
val allAdditionalTestdata: Set<File> = additionalTestDataRoot.listFiles().orEmpty().toSet()
|
||||
|
||||
val methodModelsForCoreCasesWithExistingTestData = allAdditionalTestdata.map { testDataForCase ->
|
||||
check(!testDataForCase.isFile) {
|
||||
"Expected to find only folders in testdata root ${additionalTestDataRoot.absolutePath}\n," +
|
||||
"but found a file ${testDataForCase.absolutePath}"
|
||||
}
|
||||
|
||||
check(testDataForCase.name in allCoreCasesNames) {
|
||||
"Each folder name in test data should correspond to some KPM Core Case.\n" +
|
||||
" Found folder ${testDataForCase.name}\n" +
|
||||
" All core cases: $allCoreCasesNames"
|
||||
}
|
||||
|
||||
KpmCoreCaseTestMethodModel(
|
||||
testDataForCase.name,
|
||||
additionalTestDataRoot,
|
||||
testDataForCase
|
||||
)
|
||||
}
|
||||
|
||||
val coreCasesNamesWithoutTestData = allCoreCasesNames - methodModelsForCoreCasesWithExistingTestData.mapTo(mutableSetOf()) {
|
||||
it.name
|
||||
}
|
||||
|
||||
val methodModelsForCoreCasesWithoutTestData = coreCasesNamesWithoutTestData.map {
|
||||
val expectedTestDataPath = additionalTestDataRoot.resolve(it)
|
||||
val kpmTestCaseDescriptor = KpmTestCaseDescriptor.allCaseDescriptorsByNames[it]!!
|
||||
println("Generating template sources testdata for uncovered KPM Core Case $it at ${additionalTestDataRoot.path}")
|
||||
kpmTestCaseDescriptor.generateTemplateCanonicalFileStructure(expectedTestDataPath)
|
||||
|
||||
KpmCoreCaseTestMethodModel(it, additionalTestDataRoot, expectedTestDataPath)
|
||||
}
|
||||
|
||||
return methodModelsForCoreCasesWithExistingTestData + methodModelsForCoreCasesWithoutTestData
|
||||
}
|
||||
}
|
||||
-57
@@ -1,57 +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.project.model.infra.generate
|
||||
|
||||
import org.jetbrains.kotlin.generators.*
|
||||
import org.jetbrains.kotlin.generators.model.*
|
||||
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
|
||||
import org.jetbrains.kotlin.project.model.infra.KpmCoreCasesTestRunner
|
||||
import java.io.File
|
||||
|
||||
fun generateKpmTestCases(
|
||||
dryRun: Boolean = false,
|
||||
init: TestGroupSuite.() -> Unit,
|
||||
) {
|
||||
val suite = TestGroupSuite(DefaultTargetBackendComputer).apply {
|
||||
init()
|
||||
}
|
||||
val mainClassName = TestGeneratorUtil.getMainClassName()
|
||||
suite.forEachTestClassParallel { testClass ->
|
||||
val (changed, testSourceFilePath) = NewTestGeneratorImpl(
|
||||
listOf(KpmCoreCaseTestMethodGenerator)
|
||||
).generateAndSave(testClass, dryRun, mainClassName)
|
||||
if (changed) {
|
||||
InconsistencyChecker.inconsistencyChecker(dryRun).add(testSourceFilePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NB: [testRunnersSourceRoot] is a root-folder against which will be resolved a usual java-like folder structure
|
||||
// based on packages of T
|
||||
// E.g.: testRunnersSourceRoot = "foo/bar", T == "org.jetbrains.kotlin.AbstractMyClass"
|
||||
// Then the resulting file will be created at "foo/bar/org/jetbrains/kotlin"
|
||||
inline fun <reified T : KpmCoreCasesTestRunner> TestGroupSuite.kpmRunnerWithSources(testRunnersSourceRoot: String, testSourcesPath: String) {
|
||||
testGroup(testRunnersSourceRoot, testSourcesPath) {
|
||||
testClass<T> {
|
||||
testModels += KpmCoreCasesTestClassModel(File(testSourcesPath))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun generateTestMethodsTemplateForCases(cases: Set<String>, generateTestMethodBody: (String) -> String = { "TODO()" }): String {
|
||||
return buildString {
|
||||
for (case in cases) {
|
||||
append(
|
||||
"""
|
||||
fun test$case(case: KpmTestCase) {
|
||||
${generateTestMethodBody(case)}
|
||||
}
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-111
@@ -1,111 +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.project.model.infra
|
||||
|
||||
import org.jetbrains.kotlin.project.model.KpmLocalModuleIdentifier
|
||||
import org.jetbrains.kotlin.project.model.KpmMavenModuleIdentifier
|
||||
import org.jetbrains.kotlin.project.model.nativeTarget
|
||||
import org.jetbrains.kotlin.project.model.platform
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
@Suppress("unused") // useful for debugging
|
||||
fun KpmTestCase.renderDeclarationDsl(): String {
|
||||
val p = Printer(StringBuilder())
|
||||
p.render(this)
|
||||
return p.toString()
|
||||
}
|
||||
|
||||
private fun Printer.render(case: KpmTestCase) {
|
||||
println("val ${case.name} = describeCase(\"${case.name}\") {")
|
||||
pushIndent()
|
||||
val projectsSorted = case.projects.sortedBy { it.name }
|
||||
for (project in projectsSorted) {
|
||||
render(project)
|
||||
if (project !== projectsSorted.last()) println()
|
||||
}
|
||||
popIndent()
|
||||
println("}")
|
||||
|
||||
}
|
||||
|
||||
private fun Printer.render(project: TestKpmModuleContainer) {
|
||||
println("project(\"${project.name}\") {")
|
||||
pushIndent()
|
||||
val modulesSorted = project.modules.sortedBy { it.name }
|
||||
for (module in modulesSorted) {
|
||||
render(module)
|
||||
if (module !== modulesSorted.last()) println()
|
||||
}
|
||||
popIndent()
|
||||
println("}")
|
||||
}
|
||||
|
||||
private fun Printer.render(module: TestKpmModule) {
|
||||
println("module(\"${module.name}\") {")
|
||||
pushIndent()
|
||||
val fragmentsSorted = module.fragments.sortedBy { it.name }
|
||||
|
||||
// printedFragmentDeclaration is needed for pretty-printing separating new line between fragments
|
||||
// declarations and their dependencies only in case both are present (i.e. no trailing newlines)
|
||||
var printedFragmentDeclaration = false
|
||||
for (fragment in fragmentsSorted) {
|
||||
printedFragmentDeclaration = printedFragmentDeclaration or renderFragmentDeclaration(fragment)
|
||||
}
|
||||
|
||||
for (fragment in fragmentsSorted) {
|
||||
renderFragmentDependencies(fragment, printedFragmentDeclaration)
|
||||
}
|
||||
|
||||
popIndent()
|
||||
println("}")
|
||||
}
|
||||
|
||||
private fun Printer.renderFragmentDeclaration(fragment: TestKpmFragment): Boolean {
|
||||
if (fragment.name == "common") return false
|
||||
|
||||
when {
|
||||
fragment !is TestKpmVariant -> println("fragment(\"${fragment.name}\")")
|
||||
fragment.platform == "jvm" -> println("jvm()")
|
||||
fragment.platform == "js" -> println("js()")
|
||||
fragment.nativeTarget == "linux" -> println("linux()")
|
||||
fragment.nativeTarget == "macosX64" -> println("macosX64()")
|
||||
fragment.nativeTarget == "android" -> println("android()")
|
||||
else -> error("Unknown platform: ${fragment.platform}, nativeTarget=${fragment.nativeTarget}")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun Printer.renderFragmentDependencies(fragment: TestKpmFragment, prependWithEmptyLine: Boolean) {
|
||||
var printEmptyLineOnce: Boolean = prependWithEmptyLine
|
||||
fun println(text: String) {
|
||||
if (printEmptyLineOnce) {
|
||||
this.println()
|
||||
printEmptyLineOnce = false
|
||||
}
|
||||
this.println(text)
|
||||
}
|
||||
|
||||
for (refinedFragment in fragment.declaredRefinesDependencies.sortedBy { it.name }) {
|
||||
if (refinedFragment.name == "common") continue
|
||||
println("${fragment.name} refines ${refinedFragment.name}")
|
||||
}
|
||||
|
||||
val moduleDependenciesSorted = fragment.declaredModuleDependencies.sortedBy { it.moduleIdentifier.toString() }
|
||||
for (dependencyModule in moduleDependenciesSorted) {
|
||||
when (val id = dependencyModule.moduleIdentifier) {
|
||||
is KpmLocalModuleIdentifier -> {
|
||||
val projectId = id.projectId
|
||||
println("${fragment.name} depends ${"project(\"$projectId\")"}")
|
||||
}
|
||||
|
||||
is KpmMavenModuleIdentifier -> {
|
||||
val group = id.group
|
||||
val name = id.name
|
||||
println("${fragment.name} depends ${"maven(\"$group\", \"$name\")"}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-111
@@ -1,111 +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.project.model.infra
|
||||
|
||||
import org.jetbrains.kotlin.project.model.coreCases.KpmTestCaseDescriptor
|
||||
import org.jetbrains.kotlin.project.model.coreCases.instantiateCase
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* In this file you can find support for decorating an existing [KpmTestCase] with sources
|
||||
*
|
||||
* The low-level API is [addSources]
|
||||
*
|
||||
* For the convenience, the concept of "canonical sources file structure" is introduced.
|
||||
* You can ask to generate template of this structure in designated place by calling [generateTemplateCanonicalFileStructure],
|
||||
* which is useful when you have a [KpmTestCase] and want to add some manually-written sources (test data, usually) to it.
|
||||
*
|
||||
* After that, you can use [addSourcesFromCanonicalFileStructure] to automatically decorate an existing
|
||||
* [KpmTestCase] with sources pulled from the specified folder
|
||||
*
|
||||
* See [generateTemplateCanonicalFileStructure] KDoc for details on the canonical sources file structure
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Warning! Mutates passed test case
|
||||
*/
|
||||
fun KpmTestCase.addSourcesFromCanonicalFileStructure(root: File): KpmTestCase {
|
||||
return addSources { fragment ->
|
||||
val canonicalFragmentTestdataFolder = fragment.canonicalSourceFolderAbsolute(root)
|
||||
require(canonicalFragmentTestdataFolder.exists()) {
|
||||
"Can't find testdata for fragment $fragment at ${canonicalFragmentTestdataFolder.absolutePath}"
|
||||
}
|
||||
|
||||
canonicalFragmentTestdataFolder.listFiles()?.toList().orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning! Mutates passed test case
|
||||
*/
|
||||
fun KpmTestCase.addSources(sourcesForFragment: (TestKpmFragment) -> Iterable<File>): KpmTestCase {
|
||||
val allFragments = projects.flatMap { it.modules.flatMap { it.fragments } }
|
||||
for (fragment in allFragments) {
|
||||
val sources = sourcesForFragment(fragment)
|
||||
fragment.kotlinSourceRoots.addAll(sources)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a canonical source-files structure at designated [root] for a given [KpmTestCaseDescriptor]
|
||||
*
|
||||
* In general, each [TestKpmFragment] will have a folder formed as following:
|
||||
* `root/$fragmentProject.name/$fragmentModule.name/$fragment.name`
|
||||
*
|
||||
* However, in order to reduce nesting for simple common cases, two amendments are applied:
|
||||
* - if a given [KpmTestCaseDescriptor] has only one single [TestKpmModuleContainer], then the project folder is omitted,
|
||||
* and modules of that project are embedded straight into the [root]
|
||||
* - similarly, if a given [TestKpmModuleContainer] has only one single [TestKpmModule], then the module folder is omitted,
|
||||
* and fragments of that module are embedded straight into the parent-directory.
|
||||
* This rule is applied for each project separately.
|
||||
*
|
||||
* Both amendments can be applied simultaneously, so for a test case with a single project and single module, fragments will live
|
||||
* directly inside [root]
|
||||
*/
|
||||
fun KpmTestCaseDescriptor.generateTemplateCanonicalFileStructure(root: File) {
|
||||
val case = instantiateCase()
|
||||
val allFragments = case.projects.flatMap { it.modules.flatMap { it.fragments } }
|
||||
allFragments.forEach { fragment ->
|
||||
val canonicalFragmentTestdataFolder = fragment.canonicalSourceFolderAbsolute(root)
|
||||
canonicalFragmentTestdataFolder.mkdirs()
|
||||
|
||||
val templateSources = canonicalFragmentTestdataFolder.resolve(fragment.fragmentName + ".kt")
|
||||
templateSources.writeText(PLACEHOLDER_SOURCES_TEXT)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestKpmFragment.canonicalSourceFolderAbsolute(root: File): File {
|
||||
val pathRelativeToRoot = canonicalSourceFolderRelative()
|
||||
return root.resolve(pathRelativeToRoot)
|
||||
}
|
||||
|
||||
private fun TestKpmFragment.canonicalSourceFolderRelative(): File {
|
||||
val module = containingModule
|
||||
val project = module.containingProject
|
||||
val case = project.containingCase
|
||||
|
||||
val isSingleModule = project.modules.size == 1
|
||||
val isSingleProject = case.projects.size == 1
|
||||
|
||||
val pathParts = listOfNotNull(
|
||||
project.name.takeIf { !isSingleProject },
|
||||
module.name.takeIf { !isSingleModule },
|
||||
fragmentName
|
||||
)
|
||||
|
||||
return File(pathParts.joinToString(separator = File.separator))
|
||||
}
|
||||
|
||||
private val PLACEHOLDER_SOURCES_TEXT = """
|
||||
/**
|
||||
* Generated by [org.jetbrains.kotlin.project.model.infra.${KpmTestCaseDescriptor::generateTemplateCanonicalFileStructure.name}]
|
||||
*
|
||||
* Write your testdata sources here, or remove the file, if it is not needed
|
||||
*/
|
||||
""".trimIndent()
|
||||
-24
@@ -1,24 +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.
|
||||
*/
|
||||
|
||||
@file:Suppress("UnusedReceiverParameter") // receivers are convenient for DSL scoping
|
||||
|
||||
package org.jetbrains.kotlin.project.model.testDsl
|
||||
|
||||
import org.jetbrains.kotlin.project.model.KpmLocalModuleIdentifier
|
||||
import org.jetbrains.kotlin.project.model.KpmMavenModuleIdentifier
|
||||
import org.jetbrains.kotlin.project.model.infra.KpmTestEntity
|
||||
|
||||
fun KpmTestEntity.project(projectId: String): KpmLocalModuleIdentifier = KpmLocalModuleIdentifier("", projectId, null)
|
||||
|
||||
val KpmLocalModuleIdentifier.test: KpmLocalModuleIdentifier
|
||||
get() = KpmLocalModuleIdentifier(buildId, projectId, "test")
|
||||
|
||||
// TODO: custom aux modules
|
||||
|
||||
// TODO: scopes
|
||||
fun KpmTestEntity.maven(group: String, name: String): KpmMavenModuleIdentifier = KpmMavenModuleIdentifier(group, name, null)
|
||||
|
||||
// TODO: published aux modules
|
||||
-39
@@ -1,39 +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.project.model.testDsl
|
||||
|
||||
import org.jetbrains.kotlin.project.model.infra.KpmTestCase
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmFragment
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmModule
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmModuleContainer
|
||||
|
||||
fun KpmTestCase.project(
|
||||
name: String,
|
||||
applyDefaults: Boolean = true,
|
||||
configure: TestKpmModuleContainer.() -> Unit = { }
|
||||
): TestKpmModuleContainer {
|
||||
val project = projects.getOrPut(name) { TestKpmModuleContainer(this, name) }
|
||||
if (applyDefaults) project.applyDefaults()
|
||||
project.configure()
|
||||
return project
|
||||
}
|
||||
|
||||
fun KpmTestCase.projectNamed(name: String) = projects[name]
|
||||
?: error("Project with name $name doesn't exist. Existing projects: ${projects.joinToString { it.name }}")
|
||||
|
||||
fun KpmTestCase.allModules(configure: TestKpmModule.() -> Unit) {
|
||||
projects.withAll {
|
||||
modules.withAll(configure)
|
||||
}
|
||||
}
|
||||
|
||||
fun KpmTestCase.allFragments(configure: TestKpmFragment.() -> Unit) {
|
||||
projects.withAll {
|
||||
modules.withAll {
|
||||
fragments.withAll(configure)
|
||||
}
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +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.
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package org.jetbrains.kotlin.project.model.testDsl
|
||||
|
||||
import org.jetbrains.kotlin.project.model.KpmModuleDependency
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmFragment
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmModule
|
||||
|
||||
fun TestKpmFragment.depends(module: TestKpmModule): TestKpmFragment {
|
||||
declaredModuleDependencies += KpmModuleDependency(module.moduleIdentifier)
|
||||
return this
|
||||
}
|
||||
|
||||
fun TestKpmFragment.refines(fragment: TestKpmFragment): TestKpmFragment {
|
||||
declaredRefinesDependencies += fragment
|
||||
return this
|
||||
}
|
||||
|
||||
fun TestKpmFragment.fragment(name: String, applyDefaults: Boolean = true, configure: TestKpmFragment.() -> Unit = { }): TestKpmFragment {
|
||||
return containingModule.fragment(name, applyDefaults, configure).also { subFragment -> subFragment.refines(this) }
|
||||
}
|
||||
-43
@@ -1,43 +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.
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package org.jetbrains.kotlin.project.model.testDsl
|
||||
|
||||
import org.jetbrains.kotlin.project.model.KpmLocalModuleIdentifier
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmModuleContainer
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmModule
|
||||
|
||||
fun TestKpmModuleContainer.allModules(action: TestKpmModule.() -> Unit) {
|
||||
modules.withAll(action)
|
||||
}
|
||||
|
||||
fun TestKpmModuleContainer.module(name: String, applyDefaults: Boolean = true, configure: TestKpmModule.() -> Unit = { }): TestKpmModule {
|
||||
val module = modules.getOrPut(name) {
|
||||
val id = KpmLocalModuleIdentifier(
|
||||
buildId = "",
|
||||
projectId = this.name,
|
||||
moduleClassifier = name.takeIf { it != "main" }
|
||||
)
|
||||
val module = TestKpmModule(this, id)
|
||||
if (applyDefaults) module.applyDefaults()
|
||||
|
||||
module
|
||||
}
|
||||
configure(module)
|
||||
return module
|
||||
}
|
||||
|
||||
fun TestKpmModuleContainer.moduleNamed(name: String): TestKpmModule =
|
||||
modules[name] ?: error("Module with name $name doesn't exist. Existing modules: ${modules.joinToString { it.name }}")
|
||||
|
||||
val TestKpmModuleContainer.main get() = moduleNamed("main")
|
||||
val TestKpmModuleContainer.test get() = moduleNamed("test")
|
||||
|
||||
fun TestKpmModuleContainer.depends(other: TestKpmModuleContainer): TestKpmModuleContainer {
|
||||
main.depends(other)
|
||||
return this
|
||||
}
|
||||
-52
@@ -1,52 +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.project.model.testDsl
|
||||
|
||||
import org.jetbrains.kotlin.project.model.KotlinPlatformTypeAttribute
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmFragment
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmModuleContainer
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmModule
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmVariant
|
||||
|
||||
fun TestKpmModule.fragment(name: String, applyDefaults: Boolean = true, configure: TestKpmFragment.() -> Unit = { }): TestKpmFragment {
|
||||
val result = fragments.getOrPut(name) {
|
||||
val fragment = TestKpmFragment(this, name)
|
||||
fragment
|
||||
}
|
||||
if (applyDefaults) result.applyDefaults()
|
||||
return result.also(configure)
|
||||
}
|
||||
|
||||
fun TestKpmModule.fragmentNamed(name: String): TestKpmFragment =
|
||||
fragments[name] ?: error("Fragment with name $name doesn't exist. Existing fragments ${fragments.joinToString { it.name }}")
|
||||
|
||||
fun TestKpmModule.variant(
|
||||
name: String,
|
||||
platform: String, // from KotlinPlatformTypeAttribute
|
||||
applyDefaults: Boolean = true,
|
||||
configure: TestKpmVariant.() -> Unit = { }
|
||||
): TestKpmVariant {
|
||||
val result = fragments.getOrPut(name) {
|
||||
val variant = TestKpmVariant(this, name)
|
||||
variant.variantAttributes[KotlinPlatformTypeAttribute] = platform
|
||||
variant
|
||||
} as TestKpmVariant
|
||||
if (applyDefaults) result.applyDefaults()
|
||||
result.configure()
|
||||
return result
|
||||
}
|
||||
|
||||
fun TestKpmModule.depends(otherModule: TestKpmModule): TestKpmModule {
|
||||
common.depends(otherModule)
|
||||
return this
|
||||
}
|
||||
|
||||
fun TestKpmModule.depends(otherProject: TestKpmModuleContainer): TestKpmModule {
|
||||
common.depends(otherProject.main)
|
||||
return this
|
||||
}
|
||||
|
||||
val TestKpmModule.common: TestKpmFragment get() = fragmentNamed("common")
|
||||
-32
@@ -1,32 +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.
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package org.jetbrains.kotlin.project.model.testDsl
|
||||
|
||||
import org.jetbrains.kotlin.project.model.KotlinNativeTargetAttribute
|
||||
import org.jetbrains.kotlin.project.model.KotlinPlatformTypeAttribute
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmModule
|
||||
import org.jetbrains.kotlin.project.model.infra.TestKpmVariant
|
||||
|
||||
fun TestKpmModule.jvm(configure: TestKpmVariant.() -> Unit = { }) =
|
||||
variant("jvm", KotlinPlatformTypeAttribute.JVM, configure = configure)
|
||||
|
||||
fun TestKpmModule.js(configure: TestKpmVariant.() -> Unit = { }) =
|
||||
variant("jvm", KotlinPlatformTypeAttribute.JS, configure = configure)
|
||||
|
||||
fun TestKpmModule.android(configure: TestKpmVariant.() -> Unit = { }) =
|
||||
variant("android", KotlinPlatformTypeAttribute.ANDROID_JVM, configure = configure)
|
||||
|
||||
fun TestKpmModule.nativeVariant(name: String, nativeTarget: String, configure: TestKpmVariant.() -> Unit = { }): TestKpmVariant {
|
||||
val variant = variant(name, KotlinPlatformTypeAttribute.NATIVE)
|
||||
variant.variantAttributes[KotlinNativeTargetAttribute] = nativeTarget
|
||||
variant.configure()
|
||||
return variant
|
||||
}
|
||||
|
||||
fun TestKpmModule.linux(configure: TestKpmVariant.() -> Unit = { }) = nativeVariant("linux", "linux", configure)
|
||||
fun TestKpmModule.macosX64(configure: TestKpmVariant.() -> Unit = { }) = nativeVariant("macosX64", "macosX64", configure)
|
||||
-31
@@ -1,31 +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.project.model.utils
|
||||
|
||||
import org.jetbrains.kotlin.project.model.infra.KpmTestEntity
|
||||
|
||||
class ObservableIndexedCollection<T : KpmTestEntity> private constructor(
|
||||
private val _items: MutableMap<String, T>
|
||||
) : Collection<T> by _items.values {
|
||||
constructor() : this(mutableMapOf())
|
||||
|
||||
private val allItemsActions = mutableListOf<T.() -> Unit>()
|
||||
|
||||
fun add(item: T) {
|
||||
_items[item.name] = item
|
||||
allItemsActions.forEach { action -> action(item) }
|
||||
}
|
||||
|
||||
fun withAll(action: T.() -> Unit) {
|
||||
_items.values.forEach(action)
|
||||
allItemsActions.add(action)
|
||||
}
|
||||
|
||||
fun getOrPut(name: String, defaultValue: () -> T): T =
|
||||
if (!_items.contains(name)) defaultValue().also { add(it) } else _items[name]!!
|
||||
|
||||
operator fun get(name: String): T? = _items[name]
|
||||
}
|
||||
-32
@@ -106,38 +106,6 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-project-model</artifactId>
|
||||
<version>ArtifactsTest.version</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>kotlin-stdlib-jdk7</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>kotlin-script-runtime</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>kotlin-stdlib-common</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-tooling-core</artifactId>
|
||||
|
||||
@@ -52,7 +52,6 @@ fun updateCompilerXml() {
|
||||
"libraries/tools/kotlin-noarg",
|
||||
"libraries/tools/kotlin-osgi-bundle",
|
||||
"libraries/tools/kotlin-prepush-hook",
|
||||
"libraries/tools/kotlin-project-model",
|
||||
"libraries/tools/kotlin-sam-with-receiver",
|
||||
"libraries/tools/kotlin-serialization",
|
||||
"libraries/tools/kotlin-serialization-unshaded",
|
||||
@@ -69,7 +68,6 @@ fun updateCompilerXml() {
|
||||
"native/commonizer-api",
|
||||
"libraries/examples",
|
||||
"libraries/tools/kotlin-gradle-plugin-idea-proto",
|
||||
"libraries/tools/kotlin-project-model-tests-generator",
|
||||
"repo/gradle-settings-conventions",
|
||||
"plugins/fir-plugin-prototype/plugin-annotations",
|
||||
)
|
||||
|
||||
@@ -47,7 +47,6 @@ val kotlinGradlePluginAndItsRequired = arrayOf(
|
||||
":kotlin-compiler-runner",
|
||||
":kotlin-daemon-embeddable",
|
||||
":kotlin-daemon-client",
|
||||
":kotlin-project-model",
|
||||
":kotlin-gradle-plugins-bom",
|
||||
":kotlin-gradle-plugin-api",
|
||||
":kotlin-gradle-plugin-annotations",
|
||||
|
||||
@@ -191,8 +191,6 @@ include ":kotlin-imports-dumper-compiler-plugin",
|
||||
":generators:test-generator",
|
||||
":tools:kotlinp",
|
||||
":kotlin-build-tools-enum-compat",
|
||||
":kotlin-project-model",
|
||||
":kotlin-project-model-tests-generator",
|
||||
":kotlin-gradle-compiler-types",
|
||||
":kotlin-gradle-plugin-api",
|
||||
":kotlin-gradle-plugin-annotations",
|
||||
@@ -737,8 +735,6 @@ project(':kotlin-assignment-compiler-plugin.embeddable').projectDir = "$rootDir/
|
||||
|
||||
project(':tools:kotlinp').projectDir = "$rootDir/libraries/tools/kotlinp" as File
|
||||
project(":kotlin-build-tools-enum-compat").projectDir = "$rootDir/libraries/tools/kotlin-build-tools-enum-compat" as File
|
||||
project(':kotlin-project-model').projectDir = "$rootDir/libraries/tools/kotlin-project-model" as File
|
||||
project(':kotlin-project-model-tests-generator').projectDir = "$rootDir/libraries/tools/kotlin-project-model-tests-generator" as File
|
||||
project(':kotlin-gradle-compiler-types').projectDir = "$rootDir/libraries/tools/kotlin-gradle-compiler-types" as File
|
||||
project(':kotlin-gradle-plugin-api').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin-api" as File
|
||||
project(':kotlin-gradle-plugin-annotations').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin-annotations" as File
|
||||
|
||||
Reference in New Issue
Block a user