WIP
^KT-74005
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 0741a19..62fccf0 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -4102,6 +4102,12 @@
<sha256 value="2933354de8c47ad8216ab32f220aaf5d65f280139921451683bb8b805073c7e3" origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="org.jetbrains.kotlin" name="kotlin-serialization-compiler-plugin-embeddable" version="2.0.20-RC">
+ <artifact name="kotlin-serialization-compiler-plugin-embeddable-2.0.20-RC.jar">
+ <md5 value="94272cc67751384c78c4232bd9407ea2" origin="Generated by Gradle"/>
+ <sha256 value="eaf69310210e6008abaab9de38acfddaebc684b8f312b4f3058808cf20a955c8" origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.jetbrains.kotlin" name="kotlin-serialization-compiler-plugin-embeddable" version="2.2.0-dev-4719">
<artifact name="kotlin-serialization-compiler-plugin-embeddable-2.2.0-dev-4719.jar">
<md5 value="8e85fc84ad742f939da2bbc92e70371a" origin="Generated by Gradle"/>
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/build.gradle.kts
index 6ade092..fba3379 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/build.gradle.kts
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/build.gradle.kts
@@ -44,6 +44,7 @@
val kotlinGradlePluginTest = project(":kotlin-gradle-plugin").sourceSets.named("test").map { it.output }
dependencies {
+ testImplementation(project(":kotlin-gradle-plugin", configuration = "ftConsumable"))
testImplementation(project(":kotlin-gradle-plugin")) {
capabilities {
requireCapability("org.jetbrains.kotlin:kotlin-gradle-plugin-common")
@@ -358,6 +359,11 @@
val mergedTestClassesClasspathTask = tasks.register<Copy>("testClassesCopy") {
from(kotlin.target.compilations.getByName("test").output.classesDirs)
+ from(
+ configurations.detachedConfiguration(
+ dependencies.create(dependencies.project(":kotlin-gradle-plugin", configuration = "ftConsumable"))
+ )
+ )
into(layout.buildDirectory.dir("testClassesCopy"))
}
@@ -431,7 +437,9 @@
val jdk21Provider = project.getToolchainJdkHomeFor(JdkMajorVersion.JDK_21_0)
val mavenLocalRepo = project.providers.systemProperty("maven.repo.local").orNull
- val mergedTestClassesDirectory = files(mergedTestClassesClasspathTask)
+ val mergedTestClassesDirectory = files(
+ mergedTestClassesClasspathTask,
+ )
inputs.files(mergedTestClassesDirectory)
doFirst {
systemProperty("buildScriptInjectionsClasspath", mergedTestClassesDirectory.single())
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PublishingIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PublishingIT.kt
index d68dbb2..dd8353b 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PublishingIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PublishingIT.kt
@@ -417,4 +417,4 @@
assertOutputContains("Variant myConsumableConfiguration")
}
}
-}
\ No newline at end of file
+}
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/resources/AndroidMultiplatformResourcesIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/resources/AndroidMultiplatformResourcesIT.kt
index e3128a1..563b260 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/resources/AndroidMultiplatformResourcesIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/mpp/resources/AndroidMultiplatformResourcesIT.kt
@@ -31,7 +31,7 @@
gradleVersion,
providedJdk,
androidVersion
- ).publish(PublisherConfiguration())
+ ).publish(publisherConfiguration = PublisherConfiguration())
val projectDependency = project(
"multiplatformResources/android/projectDependency",
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/argumentProviders.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/argumentProviders.kt
index 5250043..051b33d 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/argumentProviders.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/argumentProviders.kt
@@ -24,7 +24,7 @@
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class GradleTestVersions(
- val minVersion: String = TestVersions.Gradle.MIN_SUPPORTED,
+ val minVersion: String = TestVersions.Gradle.MAX_SUPPORTED,
val maxVersion: String = TestVersions.Gradle.MAX_SUPPORTED,
val additionalVersions: Array<String> = [],
)
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/KmpResolutionIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/KmpResolutionIT.kt
new file mode 100644
index 0000000..9898145
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/KmpResolutionIT.kt
@@ -0,0 +1,950 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.uklibs
+
+import org.gradle.util.GradleVersion
+import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
+import org.jetbrains.kotlin.gradle.testbase.*
+import org.jetbrains.kotlin.gradle.unitTests.uklibs.assertEqualsPP
+import org.junit.jupiter.api.DisplayName
+import org.jetbrains.kotlin.gradle.unitTests.uklibs.compilationResolution
+import org.jetbrains.kotlin.gradle.unitTests.uklibs.ResolvedComponentWithArtifacts
+
+@OptIn(ExperimentalKotlinGradlePluginApi::class)
+@MppGradlePluginTests
+@DisplayName("Test the GMT runtime behavior")
+class KmpResolutionIT : KGPBaseTest() {
+
+ @GradleTest
+ fun `smoke lenient kmp resolution - GMT and platform compilation - direct and transitive are kmp publications`(
+ version: GradleVersion
+ ) {
+ val consumer = transitiveConsumptionCase(
+ version,
+ transitiveConfiguration = {
+ buildScriptInjection {
+ project.applyMultiplatform {
+ sourceSets.commonMain.get().addIdentifierClass()
+ sourceSets.linuxMain.get().addIdentifierClass()
+ }
+ }
+ },
+ directConfiguration = {
+ buildScriptInjection {
+ project.applyMultiplatform {
+ sourceSets.commonMain.get().addIdentifierClass()
+ sourceSets.linuxMain.get().addIdentifierClass()
+ }
+ }
+ },
+ consumerConfiguration = {
+ buildScriptInjection {
+ project.setUklibResolutionStrategy()
+ }
+ }
+ )
+
+ assertEqualsPP(
+ listOf(
+ listOf("commonMain", "org.jetbrains.kotlin-kotlin-stdlib-${consumer.buildOptions.kotlinVersion}-commonMain-.klib"),
+ listOf("commonMain", "foo-transitive-1.0-commonMain-.klib"),
+ ),
+ consumer.metadataTransformationOutputClasspath("commonMain")
+ .relativeTransformationPathComponents(),
+ )
+ assertEqualsPP(
+ listOf(
+ listOf("linuxMain", "foo-direct-1.0-linuxMain-.klib"),
+ listOf("linuxMain", "foo-direct-1.0-commonMain-.klib"),
+ listOf("linuxMain", "foo-transitive-1.0-linuxMain-.klib"),
+ listOf("commonMain", "org.jetbrains.kotlin-kotlin-stdlib-${consumer.buildOptions.kotlinVersion}-commonMain-.klib"),
+ listOf("commonMain", "foo-transitive-1.0-commonMain-.klib"),
+ ),
+ consumer.metadataTransformationOutputClasspath("linuxMain")
+ .relativeTransformationPathComponents(),
+ )
+
+ val jvmDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.jvm().compilationResolution()
+ }
+ }.buildAndReturn()
+ val iosDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.iosArm64().compilationResolution()
+ }
+ }.buildAndReturn()
+ val linuxDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.linuxArm64().compilationResolution()
+ }
+ }.buildAndReturn()
+
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "metadataApiElements",
+ ),
+ "foo:transitive-jvm:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "standard-jvm",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ "org.jetbrains.kotlin.platform.type" to "jvm",
+ ),
+ ),
+ configuration = "jvmApiElements-published",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "jvmApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "standard-jvm",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "integration",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ "org.jetbrains.kotlin.platform.type" to "jvm",
+ ),
+ ),
+ configuration = "jvmApiElements",
+ ),
+ "org.jetbrains:annotations:13.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ ),
+ ),
+ configuration = "compile",
+ ),
+ ),
+ jvmDependencies,
+ )
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ // metadata jar is filtered
+ ),
+ configuration = "metadataApiElements",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ // This is a stub in stdlib publication for native
+ ),
+ configuration = "nativeApiElements",
+ ),
+ "foo:transitive-iosarm64:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "org.jetbrains.kotlin.klib",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "non-jvm",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-api",
+ "org.jetbrains.kotlin.cinteropCommonizerArtifactType" to "klib",
+ "org.jetbrains.kotlin.native.target" to "ios_arm64",
+ "org.jetbrains.kotlin.platform.type" to "native",
+ ),
+ ),
+ configuration = "iosArm64ApiElements-published",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "iosArm64ApiElements-published",
+ ),
+ ),
+ iosDependencies,
+ )
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct-linuxarm64:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "org.jetbrains.kotlin.klib",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "non-jvm",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-api",
+ "org.jetbrains.kotlin.cinteropCommonizerArtifactType" to "klib",
+ "org.jetbrains.kotlin.native.target" to "linux_arm64",
+ "org.jetbrains.kotlin.platform.type" to "native",
+ ),
+ ),
+ configuration = "linuxArm64ApiElements-published",
+ ),
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "linuxArm64ApiElements-published",
+ ),
+ "foo:transitive-linuxarm64:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "org.jetbrains.kotlin.klib",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "non-jvm",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-api",
+ "org.jetbrains.kotlin.cinteropCommonizerArtifactType" to "klib",
+ "org.jetbrains.kotlin.native.target" to "linux_arm64",
+ "org.jetbrains.kotlin.platform.type" to "native",
+ ),
+ ),
+ configuration = "linuxArm64ApiElements-published",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "linuxArm64ApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "nativeApiElements",
+ ),
+ ),
+ linuxDependencies,
+ )
+ }
+
+ @GradleTest
+ fun `smoke lenient kmp resolution - GMT and platform compilation - with direct uklib producer`(
+ version: GradleVersion
+ ) {
+ val consumer = transitiveConsumptionCase(
+ version,
+ transitiveConfiguration = {
+ buildScriptInjection {
+ project.applyMultiplatform {
+ sourceSets.commonMain.get().addIdentifierClass()
+ sourceSets.linuxMain.get().addIdentifierClass()
+ }
+ }
+ },
+ directConfiguration = {
+ buildScriptInjection {
+ project.enableUklibPublication()
+ project.applyMultiplatform {
+ // Now it can't have linuxMain due to bamboos
+ sourceSets.commonMain.get().addIdentifierClass()
+ }
+ }
+ },
+ consumerConfiguration = {
+ buildScriptInjection {
+ project.setUklibResolutionStrategy()
+ }
+ }
+ )
+
+ assertEqualsPP(
+ mutableListOf(
+ mutableListOf(
+ "commonMain", "org.jetbrains.kotlin-kotlin-stdlib-2.2.255-SNAPSHOT-commonMain-.klib",
+ ),
+ mutableListOf(
+ "commonMain", "foo-transitive-1.0-commonMain-.klib",
+ ),
+ ),
+ consumer.metadataTransformationOutputClasspath("commonMain")
+ .relativeTransformationPathComponents(),
+ )
+ assertEqualsPP(
+ mutableListOf(
+ mutableListOf(
+ "linuxMain", "uklib-foo-direct-1.0-commonMain-",
+ ),
+ mutableListOf(
+ "linuxMain", "foo-transitive-1.0-linuxMain-.klib",
+ ),
+ mutableListOf(
+ "commonMain", "org.jetbrains.kotlin-kotlin-stdlib-2.2.255-SNAPSHOT-commonMain-.klib",
+ ),
+ mutableListOf(
+ "commonMain", "foo-transitive-1.0-commonMain-.klib",
+ ),
+ ),
+ consumer.metadataTransformationOutputClasspath("linuxMain")
+ .relativeTransformationPathComponents(),
+ )
+
+ val jvmDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.jvm().compilationResolution()
+ }
+ }.buildAndReturn()
+ val iosDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.iosArm64().compilationResolution()
+ }
+ }.buildAndReturn()
+ val linuxDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.linuxArm64().compilationResolution()
+ }
+ }.buildAndReturn()
+
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ // Ignored because it doesn't have a jvm target
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "foo:transitive-jvm:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "standard-jvm",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ "org.jetbrains.kotlin.platform.type" to "jvm",
+ ),
+ ),
+ configuration = "jvmApiElements-published",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "jvmApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "standard-jvm",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "integration",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ "org.jetbrains.kotlin.platform.type" to "jvm",
+ ),
+ ),
+ configuration = "jvmApiElements",
+ ),
+ "org.jetbrains:annotations:13.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ ),
+ ),
+ configuration = "compile",
+ ),
+ ),
+ jvmDependencies,
+ )
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ // Ignored because it doesn't have an iOS target
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "foo:transitive-iosarm64:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "org.jetbrains.kotlin.klib",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "non-jvm",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-api",
+ "org.jetbrains.kotlin.cinteropCommonizerArtifactType" to "klib",
+ "org.jetbrains.kotlin.native.target" to "ios_arm64",
+ "org.jetbrains.kotlin.platform.type" to "native",
+ ),
+ ),
+ configuration = "iosArm64ApiElements-published",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "iosArm64ApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "nativeApiElements",
+ ),
+ ),
+ iosDependencies,
+ )
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "uklib",
+ "org.gradle.category" to "library",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-uklib-api",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+ "org.jetbrains.kotlin.uklibView" to "linux_arm64",
+ ),
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "foo:transitive-linuxarm64:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "org.jetbrains.kotlin.klib",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "non-jvm",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-api",
+ "org.jetbrains.kotlin.cinteropCommonizerArtifactType" to "klib",
+ "org.jetbrains.kotlin.native.target" to "linux_arm64",
+ "org.jetbrains.kotlin.platform.type" to "native",
+ ),
+ ),
+ configuration = "linuxArm64ApiElements-published",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "linuxArm64ApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "nativeApiElements",
+ ),
+ ),
+ linuxDependencies,
+ )
+ }
+
+ @GradleTest
+ fun `smoke lenient kmp resolution - GMT and platform compilation - with direct and transitive uklib producer`(
+ version: GradleVersion
+ ) {
+ val consumer = transitiveConsumptionCase(
+ version,
+ transitiveConfiguration = {
+ // transitive is regular KMP producer
+ buildScriptInjection {
+ project.enableUklibPublication()
+ project.applyMultiplatform {
+ sourceSets.commonMain.get().addIdentifierClass()
+ sourceSets.linuxMain.get().addIdentifierClass()
+ }
+ }
+ },
+ directConfiguration = {
+ // direct is Uklib producer
+ buildScriptInjection {
+ project.enableUklibPublication()
+ project.setUklibResolutionStrategy()
+ project.applyMultiplatform {
+ sourceSets.commonMain.get().addIdentifierClass()
+ }
+ }
+ },
+ consumerConfiguration = {
+ // consumer can resolve Uklibs
+ buildScriptInjection {
+ project.setUklibResolutionStrategy()
+ }
+ }
+ )
+
+ assertEqualsPP(
+ mutableListOf(
+ mutableListOf(
+ "commonMain", "org.jetbrains.kotlin-kotlin-stdlib-2.2.255-SNAPSHOT-commonMain-.klib",
+ ),
+ mutableListOf(
+ "commonMain", "uklib-foo-transitive-1.0-commonMain-",
+ ),
+ ),
+ consumer.metadataTransformationOutputClasspath("commonMain")
+ .relativeTransformationPathComponents(),
+ )
+ assertEqualsPP(
+ mutableListOf(
+ mutableListOf(
+ "linuxMain", "uklib-foo-direct-1.0-commonMain-",
+ ),
+ mutableListOf(
+ "linuxMain", "uklib-foo-transitive-1.0-linuxMain-",
+ ),
+ mutableListOf(
+ "commonMain", "org.jetbrains.kotlin-kotlin-stdlib-2.2.255-SNAPSHOT-commonMain-.klib",
+ ),
+ mutableListOf(
+ "commonMain", "uklib-foo-transitive-1.0-commonMain-",
+ ),
+ ),
+ consumer.metadataTransformationOutputClasspath("linuxMain")
+ .relativeTransformationPathComponents(),
+ )
+
+ val jvmDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.jvm().compilationResolution()
+ }
+ }.buildAndReturn()
+ val iosDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.iosArm64().compilationResolution()
+ }
+ }.buildAndReturn()
+ val linuxDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.linuxArm64().compilationResolution()
+ }
+ }.buildAndReturn()
+
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "uklib",
+ "org.gradle.category" to "library",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-uklib-api",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+ "org.jetbrains.kotlin.uklibView" to "jvm",
+ ),
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "org.jetbrains.kotlin:kotlin-dom-api-compat:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "commonFakeApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "standard-jvm",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "integration",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ "org.jetbrains.kotlin.platform.type" to "jvm",
+ ),
+ ),
+ configuration = "jvmApiElements",
+ ),
+ "org.jetbrains:annotations:13.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ ),
+ ),
+ configuration = "compile",
+ ),
+ ),
+ jvmDependencies,
+ )
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "uklib",
+ "org.gradle.category" to "library",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-uklib-api",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+ "org.jetbrains.kotlin.uklibView" to "ios_arm64",
+ ),
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "org.jetbrains.kotlin:kotlin-dom-api-compat:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "commonFakeApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "nativeApiElements",
+ ),
+ ),
+ iosDependencies,
+ )
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "uklib",
+ "org.gradle.category" to "library",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-uklib-api",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+ "org.jetbrains.kotlin.uklibView" to "linux_arm64",
+ ),
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "uklib",
+ "org.gradle.category" to "library",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-uklib-api",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+ "org.jetbrains.kotlin.uklibView" to "linux_arm64",
+ ),
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "org.jetbrains.kotlin:kotlin-dom-api-compat:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "commonFakeApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "nativeApiElements",
+ ),
+ ),
+ linuxDependencies,
+ )
+ }
+
+ @GradleTest
+ fun `smoke lenient kmp resolution - GMT and platform compilation - with transitive uklib producer through direct kmp dependency`(
+ version: GradleVersion
+ ) {
+ val consumer = transitiveConsumptionCase(
+ version,
+ transitiveConfiguration = {
+ buildScriptInjection {
+ project.enableUklibPublication()
+ project.applyMultiplatform {
+ sourceSets.commonMain.get().addIdentifierClass()
+ sourceSets.linuxMain.get().addIdentifierClass()
+ }
+ }
+ },
+ directConfiguration = {
+ buildScriptInjection {
+ project.setUklibResolutionStrategy()
+ project.applyMultiplatform {
+ sourceSets.commonMain.get().addIdentifierClass()
+ sourceSets.linuxMain.get().addIdentifierClass()
+ }
+ }
+ },
+ consumerConfiguration = {
+ buildScriptInjection {
+ project.setUklibResolutionStrategy()
+ }
+ }
+ )
+
+ assertEqualsPP(
+ mutableListOf(
+ mutableListOf(
+ "commonMain", "org.jetbrains.kotlin-kotlin-stdlib-2.2.255-SNAPSHOT-commonMain-.klib",
+ ),
+ mutableListOf(
+ "commonMain", "uklib-foo-transitive-1.0-commonMain-",
+ ),
+ ),
+ consumer.metadataTransformationOutputClasspath("commonMain")
+ .relativeTransformationPathComponents(),
+ )
+ assertEqualsPP(
+ mutableListOf(
+ mutableListOf(
+ "linuxMain", "foo-direct-1.0-linuxMain-.klib",
+ ),
+ mutableListOf(
+ "linuxMain", "foo-direct-1.0-commonMain-.klib",
+ ),
+ mutableListOf(
+ "linuxMain", "uklib-foo-transitive-1.0-linuxMain-",
+ ),
+ mutableListOf(
+ "commonMain", "org.jetbrains.kotlin-kotlin-stdlib-2.2.255-SNAPSHOT-commonMain-.klib",
+ ),
+ mutableListOf(
+ "commonMain", "uklib-foo-transitive-1.0-commonMain-",
+ ),
+ ),
+ consumer.metadataTransformationOutputClasspath("linuxMain")
+ .relativeTransformationPathComponents(),
+ )
+
+ val jvmDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.jvm().compilationResolution()
+ }
+ }.buildAndReturn()
+ val iosDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.iosArm64().compilationResolution()
+ }
+ }.buildAndReturn()
+ val linuxDependencies = consumer.buildScriptReturn {
+ project.ignoreAccessViolations {
+ kotlinMultiplatform.linuxArm64().compilationResolution()
+ }
+ }.buildAndReturn()
+
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "metadataApiElements",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "uklib",
+ "org.gradle.category" to "library",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-uklib-api",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+ "org.jetbrains.kotlin.uklibView" to "jvm",
+ ),
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "org.jetbrains.kotlin:kotlin-dom-api-compat:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "commonFakeApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "standard-jvm",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "integration",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ "org.jetbrains.kotlin.platform.type" to "jvm",
+ ),
+ ),
+ configuration = "jvmApiElements",
+ ),
+ "org.jetbrains:annotations:13.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "jar",
+ "org.gradle.category" to "library",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.isMetadataJar" to "non-a-metadata-jar",
+ ),
+ ),
+ configuration = "compile",
+ ),
+ ),
+ jvmDependencies,
+ )
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "metadataApiElements",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "uklib",
+ "org.gradle.category" to "library",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-uklib-api",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+ "org.jetbrains.kotlin.uklibView" to "ios_arm64",
+ ),
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "org.jetbrains.kotlin:kotlin-dom-api-compat:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "commonFakeApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "nativeApiElements",
+ ),
+ ),
+ iosDependencies,
+ )
+ assertEqualsPP(
+ mutableMapOf(
+ "foo:direct-linuxarm64:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "org.jetbrains.kotlin.klib",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "non-jvm",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-api",
+ "org.jetbrains.kotlin.cinteropCommonizerArtifactType" to "klib",
+ "org.jetbrains.kotlin.native.target" to "linux_arm64",
+ "org.jetbrains.kotlin.platform.type" to "native",
+ ),
+ ),
+ configuration = "linuxArm64ApiElements-published",
+ ),
+ "foo:direct:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "linuxArm64ApiElements-published",
+ ),
+ "foo:transitive:1.0" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ mutableMapOf(
+ "artifactType" to "uklib",
+ "org.gradle.category" to "library",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "kotlin-uklib-api",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+ "org.jetbrains.kotlin.uklibView" to "linux_arm64",
+ ),
+ ),
+ configuration = "uklibApiElements",
+ ),
+ "org.jetbrains.kotlin:kotlin-dom-api-compat:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "commonFakeApiElements-published",
+ ),
+ "org.jetbrains.kotlin:kotlin-stdlib:2.2.255-SNAPSHOT" to ResolvedComponentWithArtifacts(
+ artifacts = mutableListOf(
+ ),
+ configuration = "nativeApiElements",
+ ),
+ ),
+ linuxDependencies,
+ )
+ }
+
+ private fun transitiveConsumptionCase(
+ gradleVersion: GradleVersion,
+ transitiveConfiguration: TestProject.() -> Unit,
+ directConfiguration: TestProject.() -> Unit,
+ consumerConfiguration: TestProject.() -> Unit,
+ ): TestProject {
+ val transitiveProducer = project("empty", gradleVersion) {
+ settingsBuildScriptInjection {
+ settings.rootProject.name = "transitive"
+ }
+ addKgpToBuildScriptCompilationClasspath()
+ transitiveConfiguration()
+ buildScriptInjection {
+ project.applyMultiplatform {
+ js()
+ jvm()
+ iosArm64()
+ iosX64()
+ linuxArm64()
+ linuxX64()
+ }
+ }
+ }.publish(publisherConfiguration = PublisherConfiguration(group = "foo"))
+
+ val directProducer = project("empty", gradleVersion) {
+ settingsBuildScriptInjection {
+ settings.rootProject.name = "direct"
+ }
+ addKgpToBuildScriptCompilationClasspath()
+ addPublishedProjectToRepositories(transitiveProducer)
+ directConfiguration()
+ buildScriptInjection {
+ project.applyMultiplatform {
+ linuxArm64()
+ linuxX64()
+
+ sourceSets.commonMain.get().dependencies {
+ api(transitiveProducer.rootCoordinate)
+ }
+ }
+ }
+ }.publish(publisherConfiguration = PublisherConfiguration(group = "foo"))
+
+ return project("empty", gradleVersion) {
+ settingsBuildScriptInjection {
+ settings.rootProject.name = "consumer"
+ }
+ addKgpToBuildScriptCompilationClasspath()
+ addPublishedProjectToRepositories(directProducer)
+ addPublishedProjectToRepositories(transitiveProducer)
+ consumerConfiguration()
+ buildScriptInjection {
+ project.applyMultiplatform {
+ js()
+ jvm()
+ iosArm64()
+ iosX64()
+ linuxArm64()
+ linuxX64()
+
+ sourceSets.commonMain.get().dependencies {
+ implementation(directProducer.rootCoordinate)
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibConsumptionGranularMetadataTransformationIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibConsumptionGranularMetadataTransformationIT.kt
index 11ad72d..de1e3e1 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibConsumptionGranularMetadataTransformationIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibConsumptionGranularMetadataTransformationIT.kt
@@ -8,12 +8,8 @@
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
-import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
-import org.jetbrains.kotlin.gradle.plugin.mpp.locateOrRegisterMetadataDependencyTransformationTask
import org.jetbrains.kotlin.gradle.testbase.*
import org.junit.jupiter.api.DisplayName
-import java.io.File
-import kotlin.io.path.pathString
import kotlin.test.assertEquals
@OptIn(ExperimentalKotlinGradlePluginApi::class)
@@ -96,7 +92,6 @@
addPublishedProjectToRepositoriesAndIgnoreGradleMetadata(transitivePublisher)
buildScriptInjection {
project.setUklibResolutionStrategy()
- project.computeUklibChecksum(false)
project.applyMultiplatform {
iosArm64()
iosX64()
@@ -201,7 +196,7 @@
addKgpToBuildScriptCompilationClasspath()
addPublishedProjectToRepositoriesAndIgnoreGradleMetadata(publishedProject)
buildScriptInjection {
- project.computeUklibChecksum(false)
+ project.computeTransformedLibraryChecksum(false)
project.enableCrossCompilation()
project.setUklibResolutionStrategy()
project.applyMultiplatform {
@@ -231,27 +226,6 @@
}
}
- // Take full paths of the classpath formed by the GMT and extract last 2 path components for assertions
- private fun List<File>.relativeTransformationPathComponents(): List<List<String>> = map { it.lastPathComponents(2) }
- private fun File.lastPathComponents(number: Int): List<String> = toPath().toList().takeLast(number).map { it.pathString }
-
- private fun TestProject.metadataTransformationOutputClasspath(
- sourceSetName: String,
- ): List<File> {
- val iosMainTransformationTask = buildScriptReturn {
- project.locateOrRegisterMetadataDependencyTransformationTask(
- kotlinMultiplatform.sourceSets.getByName(sourceSetName)
- ).name
- }.buildAndReturn()
- val outputClasspath = buildScriptReturn {
- val transformationTask = project.locateOrRegisterMetadataDependencyTransformationTask(
- kotlinMultiplatform.sourceSets.getByName(sourceSetName)
- ).get()
- transformationTask.allTransformedLibraries().get()
- }.buildAndReturn(iosMainTransformationTask)
- return outputClasspath
- }
-
private fun publishUklib(
gradleVersion: GradleVersion,
publisherConfiguration: PublisherConfiguration,
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibConsumptionIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibConsumptionIT.kt
index 2e67fbe..0ea1a0b 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibConsumptionIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibConsumptionIT.kt
@@ -40,9 +40,9 @@
iosX64()
macosArm64()
jvm()
- js()
- wasmJs()
- wasmWasi()
+// js()
+// wasmJs()
+// wasmWasi()
}
val publisher = publishUklib(gradleVersion, androidVersion) {
project.plugins.apply("com.android.library")
@@ -425,7 +425,7 @@
addPublishedProjectToRepositoriesAndIgnoreGradleMetadata(direct)
addPublishedProjectToRepositoriesAndIgnoreGradleMetadata(transitive)
buildScriptInjection {
- project.computeUklibChecksum(false)
+ project.computeTransformedLibraryChecksum(false)
project.setUklibResolutionStrategy()
project.applyMultiplatform {
linuxArm64()
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibPublicationIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibPublicationIT.kt
index 3f576b1..b57a8b8 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibPublicationIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibPublicationIT.kt
@@ -498,6 +498,45 @@
)
}
+ @GradleTest
+ fun `uklib publication layout - we only output 1 component with Gradle metadata with appropriate number of variants`(
+ gradleVersion: GradleVersion,
+ ) {
+ val producer = publishUklib(
+ gradleVersion = gradleVersion,
+ ) {
+ jvm()
+// iosX64()
+// iosArm64()
+ sourceSets.commonMain.get().compileSource("class Common")
+ }.publishedProject
+
+ // FIXME: Finish metadata validations
+ val f = producer.rootComponent.gradleMetadata
+ println(f)
+ }
+
+ @GradleTest
+ fun `current kmp publication layout`(
+ gradleVersion: GradleVersion,
+ ) {
+ val producer = project(
+ "empty",
+ gradleVersion = gradleVersion,
+ ) {
+ addKgpToBuildScriptCompilationClasspath()
+ buildScriptInjection {
+ project.applyMultiplatform {
+ jvm()
+ sourceSets.commonMain.get().compileSource("class Common")
+ }
+ }
+ }.publish()
+
+ val f = producer.rootComponent.gradleMetadata
+ println(f)
+ }
+
@kotlinx.serialization.Serializable
data class Fragment(
val identifier: String,
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibPublicationITWIP.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibPublicationITWIP.kt
new file mode 100644
index 0000000..a004176
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibPublicationITWIP.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.uklibs
+
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.decodeFromStream
+import org.gradle.util.GradleVersion
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+import org.jetbrains.kotlin.gradle.mpp.resources.unzip
+import org.jetbrains.kotlin.gradle.testbase.*
+import org.junit.jupiter.api.DisplayName
+import java.io.FileInputStream
+import java.io.Serializable
+import java.nio.file.Path
+import kotlin.io.path.createDirectory
+import kotlin.io.path.listDirectoryEntries
+import kotlin.io.path.name
+import kotlin.test.assertEquals
+import com.android.build.api.dsl.LibraryExtension
+import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.publication.ArchiveUklibTask
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.Uklib
+import org.w3c.dom.Document
+import org.w3c.dom.Element
+import java.io.File
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.diagnostics.UklibFragmentsChecker
+
+@ExperimentalKotlinGradlePluginApi
+@MppGradlePluginTests
+@DisplayName("Smoke test uklib artifact publication")
+class UklibPublicationITWIP : KGPBaseTest() {
+
+ @GradleTest
+ fun `test`(
+ gradleVersion: GradleVersion,
+ ) {
+ val res = project("empty", gradleVersion) {
+ addKgpToBuildScriptCompilationClasspath()
+ buildScriptInjection {
+ project.applyMultiplatform {
+ iosArm64()
+ iosX64()
+ macosArm64()
+ macosX64()
+ // sourceSets.macosMain.get().compileSource("expect fun foo()")
+ applyHierarchyTemplate {
+ group("a") {
+ withIosArm64()
+ withIosX64()
+ }
+ group("b") {
+ withMacosArm64()
+ withMacosX64()
+ }
+ }
+ }
+ }
+ }.publish(publisherConfiguration = PublisherConfiguration(group = "transitive"))
+ println(res)
+ }
+
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/resolutionTesting.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/resolutionTesting.kt
new file mode 100644
index 0000000..fafbc24
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/resolutionTesting.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.uklibs
+
+import org.gradle.api.Project
+import org.gradle.api.internal.GradleInternal
+import org.gradle.api.internal.project.ProjectStateRegistry
+import org.jetbrains.kotlin.gradle.plugin.mpp.locateOrRegisterMetadataDependencyTransformationTask
+import org.jetbrains.kotlin.gradle.testbase.TestProject
+import org.jetbrains.kotlin.gradle.testbase.buildScriptReturn
+import java.io.File
+import kotlin.io.path.pathString
+
+fun <T> Project.ignoreAccessViolations(code: () -> (T)) = (project.gradle as GradleInternal).services.get(
+ ProjectStateRegistry::class.java).allowUncontrolledAccessToAnyProject { code() }
+
+fun TestProject.metadataTransformationOutputClasspath(
+ sourceSetName: String,
+): List<File> {
+ val iosMainTransformationTask = buildScriptReturn {
+ project.locateOrRegisterMetadataDependencyTransformationTask(
+ kotlinMultiplatform.sourceSets.getByName(sourceSetName)
+ ).name
+ }.buildAndReturn()
+ val outputClasspath = buildScriptReturn {
+ val transformationTask = project.locateOrRegisterMetadataDependencyTransformationTask(
+ kotlinMultiplatform.sourceSets.getByName(sourceSetName)
+ ).get()
+ transformationTask.allTransformedLibraries().get()
+ }.buildAndReturn(iosMainTransformationTask)
+ return outputClasspath
+}
+
+fun List<File>.relativeTransformationPathComponents(): List<List<String>> = map { it.lastPathComponents(2) }
+private fun File.lastPathComponents(number: Int): List<String> = toPath().toList().takeLast(number).map { it.pathString }
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/uklibTestingUtils.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/uklibTestingUtils.kt
index c2b6c98..de977f1 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/uklibTestingUtils.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/uklibTestingUtils.kt
@@ -14,8 +14,7 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.internal.properties.nativeProperties
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
-import org.jetbrains.kotlin.gradle.plugin.extraProperties
-import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.UklibResolutionStrategy
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.KmpResolutionStrategy
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.internal.compilerRunner.native.nativeCompilerClasspath
import java.io.File
@@ -60,6 +59,7 @@
val uklib: File get() = path.resolve("${artifactsPrefix}.uklib")
val jar: File get() = path.resolve("${artifactsPrefix}.jar")
val psmJar: File get() = path.resolve("${artifactsPrefix}-psm.jar")
+ val gradleMetadata: File get() = path.resolve("${artifactsPrefix}.module")
}
val rootCoordinate: String = "$group:$name:$version"
@@ -273,16 +273,17 @@
)
}
-internal fun Project.setUklibResolutionStrategy(strategy: UklibResolutionStrategy = UklibResolutionStrategy.ResolveUklibsInMavenComponents) {
+internal fun Project.setUklibResolutionStrategy(strategy: KmpResolutionStrategy = KmpResolutionStrategy.ResolveUklibsAndResolvePSMLeniently) {
propertiesExtension.set(
- PropertiesProvider.PropertyNames.KOTLIN_KMP_UKLIB_RESOLUTION_STRATEGY,
+ PropertiesProvider.PropertyNames.KOTLIN_KMP_RESOLUTION_STRATEGY,
strategy.propertyName,
)
+ computeTransformedLibraryChecksum(false)
}
-fun Project.computeUklibChecksum(enable: Boolean = false) {
+fun Project.computeTransformedLibraryChecksum(enable: Boolean = false) {
propertiesExtension.set(
- PropertiesProvider.PropertyNames.KOTLIN_MPP_COMPUTE_UKLIB_CHECKSUM,
+ PropertiesProvider.PropertyNames.KOTLIN_MPP_COMPUTE_TRANSFORMED_LIBRARY_CHECKSUM,
enable.toString(),
)
}
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/compilerArgumentUtils.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/itCompilerArgumentUtils.kt
similarity index 100%
rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/compilerArgumentUtils.kt
rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/itCompilerArgumentUtils.kt
diff --git a/libraries/tools/kotlin-gradle-plugin/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin/build.gradle.kts
index 7b76e34..c7a9bd0 100644
--- a/libraries/tools/kotlin-gradle-plugin/build.gradle.kts
+++ b/libraries/tools/kotlin-gradle-plugin/build.gradle.kts
@@ -201,6 +201,7 @@
testImplementation(project(":kotlin-gradle-statistics"))
testImplementation(project(":kotlin-tooling-metadata"))
testImplementation(libs.lincheck)
+ testImplementation(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
}
configurations.commonCompileClasspath.get().exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core")
@@ -346,58 +347,58 @@
*/
pivotVersion = KotlinMetadataPivotVersion(1, 8, 0)
}
- asmDeprecation {
- val exclusions = listOf(
- "org.jetbrains.kotlin.gradle.**", // part of the plugin
- "org.jetbrains.kotlin.project.model.**", // part of the plugin
- "org.jetbrains.kotlin.statistics.**", // part of the plugin
- "org.jetbrains.kotlin.tooling.**", // part of the plugin
- "org.jetbrains.kotlin.org.**", // already shadowed dependencies
- "org.jetbrains.kotlin.com.**", // already shadowed dependencies
- "org.jetbrains.kotlin.it.unimi.**", // already shadowed dependencies
- "org.jetbrains.kotlin.internal.**", // already internal package
- )
- val deprecationMessage = """
- You're using a Kotlin compiler class bundled into KGP for its internal needs.
- This is discouraged and will not be supported in future releases.
- The class in this artifact is scheduled for removal in Kotlin 2.2. Please define dependency on it in an alternative way.
- See https://kotl.in/gradle/internal-compiler-symbols for more details
- """.trimIndent()
- deprecateClassesByPattern("org.jetbrains.kotlin.**", deprecationMessage, exclusions)
- }
+// asmDeprecation {
+// val exclusions = listOf(
+// "org.jetbrains.kotlin.gradle.**", // part of the plugin
+// "org.jetbrains.kotlin.project.model.**", // part of the plugin
+// "org.jetbrains.kotlin.statistics.**", // part of the plugin
+// "org.jetbrains.kotlin.tooling.**", // part of the plugin
+// "org.jetbrains.kotlin.org.**", // already shadowed dependencies
+// "org.jetbrains.kotlin.com.**", // already shadowed dependencies
+// "org.jetbrains.kotlin.it.unimi.**", // already shadowed dependencies
+// "org.jetbrains.kotlin.internal.**", // already internal package
+// )
+// val deprecationMessage = """
+// You're using a Kotlin compiler class bundled into KGP for its internal needs.
+// This is discouraged and will not be supported in future releases.
+// The class in this artifact is scheduled for removal in Kotlin 2.2. Please define dependency on it in an alternative way.
+// See https://kotl.in/gradle/internal-compiler-symbols for more details
+// """.trimIndent()
+// deprecateClassesByPattern("org.jetbrains.kotlin.**", deprecationMessage, exclusions)
+// }
}
- GradlePluginVariant.values().forEach { variant ->
- if (kotlinBuildProperties.isInJpsBuildIdeaSync) return@forEach
- val sourceSet = sourceSets.getByName(variant.sourceSetName)
- val taskSuffix = sourceSet.jarTaskName.capitalize()
- val shadowJarTaskName = "$EMBEDDABLE_COMPILER_TASK_NAME$taskSuffix"
- asmDeprecation {
- val dumpTask = registerDumpDeprecationsTask(shadowJarTaskName, taskSuffix)
- val dumpAllTask = getOrCreateTask<Task>("dumpDeprecations") {
- dependsOn(dumpTask)
- }
- val expectedFileDoesNotExistMessage = """
- The file with expected deprecations for the compiler modules bundled into KGP does not exist.
- Run ./gradlew ${project.path}:${dumpTask.name} first to create it.
- You may also use ./gradlew ${project.path}:${dumpAllTask.name} to dump deprecations of all fat jars.
- Context: https://youtrack.jetbrains.com/issue/KT-70251
- """.trimIndent()
- val checkFailureMessage = """
- Expected deprecations applied to the compiler modules bundled into KGP does not match with the actually applied ones.
- Run ./gradlew ${project.path}:${dumpTask.name} to see the difference.
- You may also use ./gradlew ${project.path}:${dumpAllTask.name} to dump deprecations of all fat jars.
- Use INFO level log for the exact deprecated classes set.
- Either commit the difference or adjust the package relocation rules in ${buildFile.absolutePath}
- Please be sure to leave a comment explaining any changes related to this failure clear enough.
- Context: https://youtrack.jetbrains.com/issue/KT-70251
- """.trimIndent()
- val checkTask =
- registerCheckDeprecationsTask(shadowJarTaskName, taskSuffix, expectedFileDoesNotExistMessage, checkFailureMessage)
- named("check") {
- dependsOn(checkTask)
- }
- }
- }
+// GradlePluginVariant.values().forEach {
+// if (kotlinBuildProperties.isInJpsBuildIdeaSync) return@forEach
+// val sourceSet = sourceSets.getByName(variant.sourceSetName)
+// val taskSuffix = sourceSet.jarTaskName.capitalize()
+// val shadowJarTaskName = "$EMBEDDABLE_COMPILER_TASK_NAME$taskSuffix"
+// asmDeprecation {
+// val dumpTask = registerDumpDeprecationsTask(shadowJarTaskName, taskSuffix)
+// val dumpAllTask = getOrCreateTask<Task>("dumpDeprecations") {
+// dependsOn(dumpTask)
+// }
+// val expectedFileDoesNotExistMessage = """
+// The file with expected deprecations for the compiler modules bundled into KGP does not exist.
+// Run ./gradlew ${project.path}:${dumpTask.name} first to create it.
+// You may also use ./gradlew ${project.path}:${dumpAllTask.name} to dump deprecations of all fat jars.
+// Context: https://youtrack.jetbrains.com/issue/KT-70251
+// """.trimIndent()
+// val checkFailureMessage = """
+// Expected deprecations applied to the compiler modules bundled into KGP does not match with the actually applied ones.
+// Run ./gradlew ${project.path}:${dumpTask.name} to see the difference.
+// You may also use ./gradlew ${project.path}:${dumpAllTask.name} to dump deprecations of all fat jars.
+// Use INFO level log for the exact deprecated classes set.
+// Either commit the difference or adjust the package relocation rules in ${buildFile.absolutePath}
+// Please be sure to leave a comment explaining any changes related to this failure clear enough.
+// Context: https://youtrack.jetbrains.com/issue/KT-70251
+// """.trimIndent()
+// val checkTask =
+// registerCheckDeprecationsTask(shadowJarTaskName, taskSuffix, expectedFileDoesNotExistMessage, checkFailureMessage)
+// named("check") {
+// dependsOn(checkTask)
+// }
+// }
+// }
}
tasks.named("validatePlugins") {
@@ -488,7 +489,17 @@
}
}
+ val ftConsumable = configurations.create("ftConsumable") {
+ isCanBeConsumed = true
+ isCanBeResolved = false
+ }
val functionalTestCompilation = kotlin.target.compilations.getByName("functionalTest")
+ functionalTestCompilation.output.classesDirs.forEach {
+ ftConsumable.outgoing.artifact(it) {
+ builtBy(functionalTestCompilation.compileTaskProvider)
+ }
+ }
+
functionalTestCompilation.compileJavaTaskProvider.configure {
sourceCompatibility = JavaLanguageVersion.of(17).toString()
targetCompatibility = JavaLanguageVersion.of(17).toString()
@@ -498,6 +509,10 @@
kotlinJavaToolchain.toolchain.use(project.getToolchainLauncherFor(JdkMajorVersion.JDK_17_0))
}
}
+ functionalTestCompilation.configurations.pluginConfiguration.dependencies.add(
+ // FIXME: Do we intentionally use different kotlin versions with BTA impl and without? Or how does this even work?
+ dependencies.create("org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable:${libs.versions.kotlin.`for`.gradle.plugins.compilation.get()}")
+ )
functionalTestCompilation.associateWith(kotlin.target.compilations.getByName(gradlePluginVariantForFunctionalTests.sourceSetName))
functionalTestCompilation.associateWith(kotlin.target.compilations.getByName("common"))
@@ -562,10 +577,11 @@
}
implementation("org.reflections:reflections:0.10.2")
implementation(project(":compose-compiler-gradle-plugin"))
+ implementation(libs.kotlinx.serialization.json)
}
tasks.named("check") {
dependsOn("functionalTest")
dependsOn("lincheckTest")
}
-}
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/stdlibDependencyManagement.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/stdlibDependencyManagement.kt
index 0140d41..b35004e 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/stdlibDependencyManagement.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/stdlibDependencyManagement.kt
@@ -136,7 +136,7 @@
val stdlibModule = compilation.platformType.stdlibPlatformType(this, kotlinSourceSet, stdlibVersion >= kotlin1920Version)
?: return@withDependencies
- KotlinStdlibConfigurationMetrics.collectMetrics(project, requestedStdlibVersion)
+// KotlinStdlibConfigurationMetrics.collectMetrics(project, requestedStdlibVersion)
dependencySet.addLater(
coreLibrariesVersion.map {
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt
index 37bbceb..4b8879d 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt
@@ -10,7 +10,7 @@
import org.gradle.api.provider.Provider
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.compilerRunner.KotlinCompilerArgumentsLogLevel
-import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.UklibResolutionStrategy
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.KmpResolutionStrategy
import org.jetbrains.kotlin.gradle.dsl.NativeCacheOrchestration
import org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode
import org.jetbrains.kotlin.gradle.internal.properties.PropertiesBuildService
@@ -35,7 +35,7 @@
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_ANDROID_STYLE_NO_WARN
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ANDROID_SOURCE_SET_LAYOUT_VERSION
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_APPLY_DEFAULT_HIERARCHY_TEMPLATE
-import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_COMPUTE_UKLIB_CHECKSUM
+import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_COMPUTE_TRANSFORMED_LIBRARY_CHECKSUM
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_INTRANSITIVE_METADATA_CONFIGURATION
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_OPTIMISTIC_NUMBER_COMMONIZATION
@@ -47,7 +47,7 @@
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_IMPORT_ENABLE_SLOW_SOURCES_JAR_RESOLVER
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_RESOURCES_RESOLUTION_STRATEGY
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_FAKE_UKLIB_TRANSFORMS
-import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_KMP_UKLIB_RESOLUTION_STRATEGY
+import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_KMP_RESOLUTION_STRATEGY
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_SUPPRESS_EXPERIMENTAL_ARTIFACTS_DSL_WARNING
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_PUBLISH_JVM_ENVIRONMENT_ATTRIBUTE
@@ -187,18 +187,18 @@
val publishUklib: Boolean
get() = booleanProperty(KOTLIN_MPP_PUBLISH_UKLIB) ?: false
- val uklibResolutionStrategy: UklibResolutionStrategy
- get() = this.get(KOTLIN_KMP_UKLIB_RESOLUTION_STRATEGY)?.let {
- UklibResolutionStrategy.fromProperty(it)
- } ?: UklibResolutionStrategy.IgnoreUklibs
+ val kmpResolutionStrategy: KmpResolutionStrategy
+ get() = this.get(KOTLIN_KMP_RESOLUTION_STRATEGY)?.let {
+ KmpResolutionStrategy.fromProperty(it)
+ } ?: KmpResolutionStrategy.StandardKMPResolution
// This property makes transforms noop and is used in functionalTest resolution tests
val fakeUkibTransforms: Boolean
get() = booleanProperty(KOTLIN_MPP_FAKE_UKLIB_TRANSFORMS) ?: false
// This property disables -${checksum} output path suffix in the GMT transformed output klib to make them testable
- val computeUklibChecksum: Boolean
- get() = booleanProperty(KOTLIN_MPP_COMPUTE_UKLIB_CHECKSUM) ?: true
+ val computeTransformedLibraryChecksum: Boolean
+ get() = booleanProperty(KOTLIN_MPP_COMPUTE_TRANSFORMED_LIBRARY_CHECKSUM) ?: true
val enableKotlinToolingMetadataArtifact: Boolean
get() = booleanProperty("kotlin.mpp.enableKotlinToolingMetadataArtifact") ?: true
@@ -689,7 +689,7 @@
val KOTLIN_JS_YARN = property("kotlin.js.yarn")
val KOTLIN_MPP_PUBLISH_UKLIB = property("kotlin.mpp.publishUklib")
val KOTLIN_MPP_FAKE_UKLIB_TRANSFORMS = property("kotlin.internal.mpp.fakeUklibTransforms")
- val KOTLIN_MPP_COMPUTE_UKLIB_CHECKSUM = property("kotlin.internal.mpp.computeUklibChecksum")
+ val KOTLIN_MPP_COMPUTE_TRANSFORMED_LIBRARY_CHECKSUM = property("kotlin.internal.mpp.computeTransformedLibraryChecksum")
val KOTLIN_MPP_ENABLE_GRANULAR_SOURCE_SETS_METADATA = property("kotlin.mpp.enableGranularSourceSetsMetadata")
val KOTLIN_MPP_ENABLE_COMPATIBILITY_METADATA_VARIANT = property("kotlin.mpp.enableCompatibilityMetadataVariant")
val KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION = property("kotlin.mpp.enableCInteropCommonization")
@@ -741,7 +741,7 @@
val KOTLIN_SWIFT_EXPORT_ENABLED = property("kotlin.experimental.swift-export.enabled")
val KOTLIN_NATIVE_ENABLE_KLIBS_CROSSCOMPILATION = property("kotlin.native.enableKlibsCrossCompilation")
val KOTLIN_ARCHIVES_TASK_OUTPUT_AS_FRIEND_ENABLED = property("kotlin.build.archivesTaskOutputAsFriendModule")
- val KOTLIN_KMP_UKLIB_RESOLUTION_STRATEGY = property("kotlin.kmp.uklibResolutionStrategy")
+ val KOTLIN_KMP_RESOLUTION_STRATEGY = property("kotlin.internal.kmp.kmpResolutionStrategy")
val KOTLIN_KMP_ISOLATED_PROJECT_SUPPORT = property("kotlin.kmp.isolated-projects.support")
val KOTLIN_INCREMENTAL_FIR = property("kotlin.incremental.jvm.fir")
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompositeMetadataArtifactImpl.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompositeMetadataArtifactImpl.kt
index 7407f87..9b3c470 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompositeMetadataArtifactImpl.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompositeMetadataArtifactImpl.kt
@@ -21,7 +21,8 @@
override val moduleDependencyVersion: String,
private val kotlinProjectStructureMetadata: KotlinProjectStructureMetadata,
private val primaryArtifactFile: File,
- private val hostSpecificArtifactFilesBySourceSetName: Map<String, File>
+ private val hostSpecificArtifactFilesBySourceSetName: Map<String, File>,
+ private val computeChecksum: Boolean = true,
) : CompositeMetadataArtifact {
override fun exists(): Boolean {
@@ -107,7 +108,7 @@
?: SourceSetMetadataLayout.METADATA.archiveExtension
override val checksum: String
- get() = artifactFile.checksum
+ get() = if (computeChecksum) artifactFile.checksum else ""
/**
* Example:
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt
index 77dc22f..07e5377 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt
@@ -31,6 +31,7 @@
import org.jetbrains.kotlin.gradle.plugin.mpp.internal.projectStructureMetadataResolvedConfiguration
import org.jetbrains.kotlin.gradle.plugin.mpp.publishing.KotlinProjectCoordinatesData
import org.jetbrains.kotlin.gradle.plugin.mpp.publishing.consumeRootModuleCoordinates
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.KmpResolutionStrategy
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.utils.*
import java.io.File
@@ -121,7 +122,8 @@
val sourceSetMetadataLocationsOfProjectDependencies: KotlinProjectSharedDataProvider<SourceSetMetadataLocations>,
val transformProjectDependencies: Boolean,
val uklibFragmentAttributes: Set<String>,
- val computeUklibChecksum: Boolean,
+ val computeTransformedLibraryChecksum: Boolean,
+ val kmpResolutionStrategy: KmpResolutionStrategy,
) {
constructor(project: Project, kotlinSourceSet: KotlinSourceSet, transformProjectDependencies: Boolean = true) : this(
build = project.currentBuild,
@@ -145,7 +147,8 @@
.consumeCommonSourceSetMetadataLocations(kotlinSourceSet.internal.resolvableMetadataConfiguration),
transformProjectDependencies = transformProjectDependencies,
uklibFragmentAttributes = kotlinSourceSet.metadataFragmentAttributes.map { it.safeToConsume() }.toSet(),
- computeUklibChecksum = project.kotlinPropertiesProvider.computeUklibChecksum,
+ computeTransformedLibraryChecksum = project.kotlinPropertiesProvider.computeTransformedLibraryChecksum,
+ kmpResolutionStrategy = project.kotlinPropertiesProvider.kmpResolutionStrategy,
)
}
@@ -304,11 +307,11 @@
attributes = uklibFragmentAttributes,
)
if (allVisibleFragments.isEmpty()) {
- throw UklibIsMissingRequiredAttributesException(
- unzippedUklib = upackedUklibDirectory.file,
- targetFragmentAttribute = uklibFragmentAttributes.sorted(),
- availablePlatformFragments = uklibDependency.module.fragments.map { it.identifier }.sorted(),
- )
+// throw UklibIsMissingRequiredAttributesException(
+// unzippedUklib = upackedUklibDirectory.file,
+// targetFragmentAttribute = uklibFragmentAttributes.sorted(),
+// availablePlatformFragments = uklibDependency.module.fragments.map { it.identifier }.sorted(),
+// )
}
val fragmentsVisibleByThisSourceSet = allVisibleFragments.filterNot {
@@ -334,7 +337,7 @@
moduleVersion?.version ?: "unspecified",
),
uklibDependency.module.fragments.toList(),
- params.computeUklibChecksum,
+ params.computeTransformedLibraryChecksum,
)
)
)
@@ -364,7 +367,8 @@
params.sourceSetName,
dependency,
projectStructureMetadata,
- isResolvedToProject
+ isResolvedToProject,
+ resolveWithLenientPSMResolutionScheme = params.kmpResolutionStrategy == KmpResolutionStrategy.ResolveUklibsAndResolvePSMLeniently
)
val allVisibleSourceSets = sourceSetVisibility.visibleSourceSetNames
@@ -383,7 +387,11 @@
val transitiveDependenciesToVisit = module.dependencies
.filterIsInstance<ResolvedDependencyResult>()
- .filterTo(mutableSetOf()) { it.toModuleDependencyIdentifier() in requestedTransitiveDependencies }
+ .filterTo(mutableSetOf()) {
+ it.toModuleDependencyIdentifier() in requestedTransitiveDependencies
+ // Don't filter dependencies in PSM with the lenient resolution model. This is slightly incorrect, but means we see transitive dependencies as in interlibrary dependencies
+ || params.kmpResolutionStrategy == KmpResolutionStrategy.ResolveUklibsAndResolvePSMLeniently
+ }
if (params.sourceSetName in params.platformCompilationSourceSets && !isResolvedToProject)
return MetadataDependencyResolution.Exclude.PublishedPlatformSourceSetDependency(module, transitiveDependenciesToVisit)
@@ -446,7 +454,8 @@
moduleDependencyVersion = module.moduleVersion?.version ?: "unspecified",
kotlinProjectStructureMetadata = projectStructureMetadata,
primaryArtifactFile = compositeMetadataArtifact.file,
- hostSpecificArtifactFilesBySourceSetName = hostSpecificMetadataArtifactBySourceSet
+ hostSpecificArtifactFilesBySourceSetName = hostSpecificMetadataArtifactBySourceSet,
+ computeChecksum = params.computeTransformedLibraryChecksum
)
)
}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt
index b90df5b..06a6fea 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt
@@ -33,6 +33,7 @@
import org.jetbrains.kotlin.gradle.plugin.attributes.KlibPackaging
import org.jetbrains.kotlin.gradle.plugin.await
import org.jetbrains.kotlin.gradle.plugin.mpp.publishing.kotlinMultiplatformRootPublication
+import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
import org.jetbrains.kotlin.gradle.targets.metadata.*
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
@@ -48,6 +49,8 @@
private val metadataTarget get() = project.multiplatformExtension.metadataTarget
+ internal val uklibUsages: CompletableFuture<List<DefaultKotlinUsageContext>> = CompletableFuture()
+
internal suspend fun subcomponentTargets(): List<KotlinTarget> {
AfterFinaliseCompilations.await()
return kotlinTargets
@@ -66,7 +69,20 @@
}.toSet()
}
- override fun getVariants(): Set<SoftwareComponent> = _variants.getOrThrow()
+ override fun getVariants(): Set<SoftwareComponent> = if (project.kotlinPropertiesProvider.publishUklib) emptySet() else _variants.getOrThrow()
+
+ private val allUklibUsages: Future<Set<UsageContext>> = project.future {
+ if (project.kotlinPropertiesProvider.publishUklib) {
+ // FIXME: Is there a sane API to get jvm component as a bunch of variants???
+// val foo = (project.components.named("java") as ComponentWithVariants)
+// println(foo)
+// println(project)
+ // FIXME: Drop this KotlinSoftwareComponent garbage and use adhoc component factory when publishing with uklibs. This component maybe should go into a separate -legacy component
+ return@future uklibUsages.await().toSet()
+ } else {
+ return@future emptySet()
+ }
+ }
private val _usages: Future<Set<DefaultKotlinUsageContext>> = project.future {
metadataTarget.awaitMetadataCompilationsCreated()
@@ -76,6 +92,10 @@
return@future metadataTarget.createUsageContexts(metadataCompilation)
}
+ if (project.kotlinPropertiesProvider.publishUklib) {
+ return@future emptySet()
+ }
+
mutableSetOf<DefaultKotlinUsageContext>().apply {
val allMetadataJar = project.tasks.named(KotlinMetadataTargetConfigurator.ALL_METADATA_JAR_NAME)
val allMetadataArtifact = project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, allMetadataJar) { allMetadataArtifact ->
@@ -105,7 +125,7 @@
override fun getUsages(): Set<UsageContext> {
- return _usages.getOrThrow().publishableUsages() + includeExtraUsagesFrom.usages
+ return _usages.getOrThrow().publishableUsages() + includeExtraUsagesFrom.usages + allUklibUsages.getOrThrow()
}
private suspend fun allPublishableCommonSourceSets() = getCommonSourceSetsForMetadataCompilation(project) +
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt
index 3f8665f..18893f8 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinUsages.kt
@@ -23,6 +23,9 @@
const val KOTLIN_RUNTIME = "kotlin-runtime"
const val KOTLIN_METADATA = "kotlin-metadata"
+ const val KOTLIN_UKLIB_API = "kotlin-uklib-api"
+ const val KOTLIN_UKLIB_RUNTIME = "kotlin-uklib-runtime"
+
// This type is required to distinguish metadata jar configuration from a psm secondary variant.
// At the same time, disambiguation and compatibility rules should count them as equivalent
// to be possible to apply a transform actions chain to `kotlin-metadata` artifact to get psm.
@@ -162,7 +165,7 @@
private class KotlinMetadataDisambiguation : AttributeDisambiguationRule<Usage> {
override fun execute(details: MultipleCandidatesDetails<Usage>) = details.run {
- val commonCandidateList = listOf(KOTLIN_METADATA, KOTLIN_API, *javaUsagesForKotlinMetadataConsumers.toTypedArray())
+ val commonCandidateList = listOf(KOTLIN_METADATA, KOTLIN_UKLIB_API, KOTLIN_API, *javaUsagesForKotlinMetadataConsumers.toTypedArray())
if (consumerValue?.name == KOTLIN_METADATA) {
// Prefer Kotlin metadata, but if there's no such variant then accept 'kotlin-api' or the Java usages
// (see the compatibility rule):
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/MetadataDependencyTransformationTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/MetadataDependencyTransformationTask.kt
index 9f46c4f..c9910d4 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/MetadataDependencyTransformationTask.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/MetadataDependencyTransformationTask.kt
@@ -109,7 +109,9 @@
flatMap { resolution ->
when (resolution) {
is MetadataDependencyResolution.ChooseVisibleSourceSets -> resolution.toTransformedLibrariesRecords()
- is MetadataDependencyResolution.KeepOriginalDependency -> resolution.toTransformedLibrariesRecords()
+ is MetadataDependencyResolution.KeepOriginalDependency -> emptyList()
+ // wtf why??? Due to compatibility rules in uklibs and dom-api-compat attributes we can get dom-api-compat-in-metadata, but when would we ever want to get this dependency in the classpath???
+// resolution.toTransformedLibrariesRecords()
is MetadataDependencyResolution.Exclude -> emptyList()
}
}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt
index f3b53c0..f5c90cf 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/SourceSetVisibilityProvider.kt
@@ -10,6 +10,7 @@
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.artifacts.result.ResolvedDependencyResult
+import org.gradle.api.attributes.Attribute
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
@@ -85,18 +86,31 @@
resolvedRootMppDependency: ResolvedDependencyResult,
dependencyProjectStructureMetadata: KotlinProjectStructureMetadata,
resolvedToOtherProject: Boolean,
+ resolveWithLenientPSMResolutionScheme: Boolean,
): SourceSetVisibilityResult {
val resolvedRootMppDependencyId = resolvedRootMppDependency.selected.id
val platformCompilationsByResolvedVariantName = mutableMapOf<String, PlatformCompilationData>()
- val visiblePlatformVariantNames: List<Set<String>> = platformCompilations
- .filter { visibleFromSourceSet in it.allSourceSets }
+ val compilationsContainingSourceSetDoingGMT = platformCompilations.filter { visibleFromSourceSet in it.allSourceSets }
+
+ val visiblePlatformVariantNames: List<Set<String>> = compilationsContainingSourceSetDoingGMT
.mapNotNull { platformCompilationData ->
val resolvedPlatformDependencies = platformCompilationData
.resolvedDependenciesConfiguration
.allResolvedDependencies
.filter { it.selected.id isEqualsIgnoringVersion resolvedRootMppDependencyId }
+ .filterNot {
+ // Pre lenient resolve logic
+ if (!resolveWithLenientPSMResolutionScheme) return@filterNot false
+ // Filter metadata jars resolved from pre Uklib KMP publications
+ // @see [KotlinPlatformConfigurationsCanResolveMetadata]
+ it.resolvedVariant.attributes.getAttribute(
+ KotlinPlatformType.attribute
+ ) == KotlinPlatformType.common || it.resolvedVariant.attributes.getAttribute(
+ Attribute.of(KotlinPlatformType.attribute.name, String::class.java)
+ ) == KotlinPlatformType.common.name
+ }
/*
Returning null if we can't find the given dependency in a certain platform compilations dependencies.
This is not expected, since this means the dependency does not support the given targets which will
@@ -128,6 +142,11 @@
return SourceSetVisibilityResult(emptySet(), emptyMap())
}
+ // Means we are looking at a dependency with a subset of targets relative to this source set. Ignore this dependency in this source set
+ if (resolveWithLenientPSMResolutionScheme && compilationsContainingSourceSetDoingGMT.size > visiblePlatformVariantNames.size) {
+ return SourceSetVisibilityResult(emptySet(), emptyMap())
+ }
+
val visibleSourceSetNames = visiblePlatformVariantNames
.mapNotNull { platformVariants ->
platformVariants
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/publishing/Publishing.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/publishing/Publishing.kt
index 3439137..4e936f3 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/publishing/Publishing.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/publishing/Publishing.kt
@@ -12,10 +12,10 @@
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.internal.publication.MavenPublicationInternal
-import org.gradle.jvm.tasks.Jar
+import org.jetbrains.kotlin.gradle.dsl.awaitMetadataTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.Uklib
import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.publication.UklibPomDependenciesRewriter
-import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.publication.locateOrRegisterArchiveUklibTask
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.publication.createUklibPublication
import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.publication.locateOrStubJvmJarTask
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.*
@@ -90,10 +90,9 @@
UklibPomDependenciesRewriter().rewriteDependencies(it, scopeRewritingMapping.get())
}
project.launch {
- artifact(project.locateOrStubJvmJarTask())
- artifact(project.locateOrRegisterArchiveUklibTask()) { artifact ->
- artifact.extension = Uklib.UKLIB_EXTENSION
- }
+ rootComponent.uklibUsages.complete(
+ project.createUklibPublication()
+ )
}
}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/KmpResolutionStrategy.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/KmpResolutionStrategy.kt
new file mode 100644
index 0000000..63c06b7
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/KmpResolutionStrategy.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption
+
+internal enum class KmpResolutionStrategy {
+ ResolveUklibsAndResolvePSMLeniently,
+ /**
+ * FIXME: Introduce two modes of Uklib resolution
+ * - Prefer Uklib variants
+ * - Prefer PSM variants
+ */
+ StandardKMPResolution;
+
+ val propertyName: String
+ get() = when (this) {
+ ResolveUklibsAndResolvePSMLeniently -> "resolveUklibsAndResolvePSMLeniently"
+ StandardKMPResolution -> "standardKMPResolution"
+ }
+
+ companion object {
+ fun fromProperty(name: String): KmpResolutionStrategy? = when (name) {
+ ResolveUklibsAndResolvePSMLeniently.propertyName -> ResolveUklibsAndResolvePSMLeniently
+ StandardKMPResolution.propertyName -> StandardKMPResolution
+ else -> null
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/ThrowAwayMetadataJarsTransform.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/ThrowAwayMetadataJarsTransform.kt
new file mode 100644
index 0000000..b06bc13
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/ThrowAwayMetadataJarsTransform.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption
+
+import org.gradle.api.artifacts.transform.InputArtifact
+import org.gradle.api.artifacts.transform.TransformAction
+import org.gradle.api.artifacts.transform.TransformOutputs
+import org.gradle.api.artifacts.transform.TransformParameters
+import org.gradle.api.file.FileSystemLocation
+import org.gradle.api.provider.Property
+import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.PathSensitive
+import org.gradle.api.tasks.PathSensitivity
+import org.gradle.work.DisableCachingByDefault
+import java.util.zip.ZipFile
+
+@DisableCachingByDefault(because = "Investigate caching uklib transforms")
+internal abstract class ThrowAwayMetadataJarsTransform : TransformAction<ThrowAwayMetadataJarsTransform.Parameters> {
+ interface Parameters : TransformParameters {
+ @get:Input
+ // FIXME: Fake metadata jar?
+ val fakeUklibUnzip: Property<Boolean>
+ }
+
+ @get:PathSensitive(PathSensitivity.RELATIVE)
+ @get:InputArtifact
+ abstract val inputArtifact: Provider<FileSystemLocation>
+
+ override fun transform(outputs: TransformOutputs) {
+ val jar = inputArtifact.get().asFile
+ // Sanity check
+ if (jar.extension != "jar") {
+ // Just return whatever this is
+ outputs.file(jar)
+ return
+ }
+
+ val isMetadataJar: Boolean = if (parameters.fakeUklibUnzip.get())
+ false
+ else ZipFile(jar).use { zip ->
+ zip.entries().asSequence().any {
+ it.name.endsWith("kotlin-project-structure-metadata.json")
+ }
+ }
+ // Return nothing on metadata jar
+ if (isMetadataJar) return
+ outputs.file(jar)
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibConsumptionSetupAction.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibConsumptionSetupAction.kt
index d264d89..1ac5905 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibConsumptionSetupAction.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibConsumptionSetupAction.kt
@@ -8,12 +8,18 @@
import org.gradle.api.NamedDomainObjectCollection
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
+import org.gradle.api.attributes.*
+import org.gradle.api.attributes.Usage.*
import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.uklibFragmentPlatformAttribute
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.*
-import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseCompilations
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.*
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages.KOTLIN_API
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages.KOTLIN_METADATA
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages.KOTLIN_RUNTIME
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages.KOTLIN_UKLIB_API
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages.KOTLIN_UKLIB_RUNTIME
import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.Uklib
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
@@ -21,9 +27,9 @@
import org.jetbrains.kotlin.gradle.utils.setAttribute
internal val UklibConsumptionSetupAction = KotlinProjectSetupAction {
- when (project.kotlinPropertiesProvider.uklibResolutionStrategy) {
- UklibResolutionStrategy.ResolveUklibsInMavenComponents -> setupUklibConsumption()
- UklibResolutionStrategy.IgnoreUklibs -> { /* do nothing */ }
+ when (project.kotlinPropertiesProvider.kmpResolutionStrategy) {
+ KmpResolutionStrategy.ResolveUklibsAndResolvePSMLeniently -> setupUklibConsumption()
+ KmpResolutionStrategy.StandardKMPResolution -> { /* do nothing */ }
}
}
@@ -37,10 +43,15 @@
val sourceSets = multiplatformExtension.sourceSets
val targets = multiplatformExtension.targets
+ dependencies.attributesSchema.attribute(USAGE_ATTRIBUTE) { strategy ->
+ strategy.compatibilityRules.add(KotlinApiMetadataAndRuntimeCanConsumeKotlinUklibApi::class.java)
+ }
+
registerCompressedUklibArtifact()
allowUklibsToDecompress()
allowMetadataConfigurationsToResolveUnzippedUklib(sourceSets)
allowPlatformCompilationsToResolvePlatformCompilationArtifactFromUklib(targets)
+ allowPSMBasedKMPToResolveLeniently(targets)
}
private fun Project.allowPlatformCompilationsToResolvePlatformCompilationArtifactFromUklib(
@@ -76,6 +87,16 @@
// FIXME: Refactor this and encode what configurations should be allowed to transform per KotlinTarget somewhere around [uklibFragmentPlatformAttribute]
target.compilations.configureEach {
+ // We have to invert all resolvable configurations, so that they don't prefer jvm compatibility variant in uklib publication
+ with(it.internal.configurations.compileDependencyConfiguration.attributes) {
+ setAttribute(USAGE_ATTRIBUTE, usageByName(KOTLIN_UKLIB_API))
+ }
+ it.internal.configurations.runtimeDependencyConfiguration?.attributes?.let {
+ with(it) {
+ setAttribute(USAGE_ATTRIBUTE, usageByName(KOTLIN_UKLIB_RUNTIME))
+ }
+ }
+
listOfNotNull(
it.internal.configurations.compileDependencyConfiguration,
it.internal.configurations.runtimeDependencyConfiguration,
@@ -115,4 +136,126 @@
}
}
+private class KotlinApiMetadataAndRuntimeCanConsumeKotlinUklibApi : AttributeCompatibilityRule<Usage> {
+ override fun execute(details: CompatibilityCheckDetails<Usage>) = with(details) {
+ val consumerUsage = consumerValue?.name ?: return@with
+ val producerUsage = producerValue?.name ?: return@with
+ // Allow consuming Uklibs in all existing configurations
+ if (
+ mapOf(
+ KOTLIN_METADATA to setOf(KOTLIN_UKLIB_API),
+// KOTLIN_API to setOf(KOTLIN_UKLIB_API),
+// KOTLIN_RUNTIME to setOf(KOTLIN_UKLIB_API, KOTLIN_UKLIB_RUNTIME),
+ )[consumerUsage]?.contains(producerUsage) == true
+ ) compatible()
+ }
+}
+/**
+ * Use a nuclear compatibility rules to allow lenient interlibrary resolution of KMP dependencies. When platform configuration is going to
+ * resolve for GMT or for platform compilation, it will be allowed to fallback to metadata variant. S
+ *
+ * - Klib compilations already filter out jar files
+ * - For GMT there is further special handling
+ * - FIXME: jvm and android will receive 1 garbage jar? Can we write a transform to check for metadata jar? Check for presence of META-INF/kotlin-project-structure-metadata.json?
+ */
+private fun Project.allowPSMBasedKMPToResolveLeniently(
+ targets: NamedDomainObjectCollection<KotlinTarget>
+) {
+ dependencies.attributesSchema.attribute(USAGE_ATTRIBUTE) { strategy ->
+ strategy.compatibilityRules.add(AllowPlatformConfigurationsToFallBackToMetadataForLenientKmpResolutionUsage::class.java)
+ strategy.disambiguationRules.add(DisambiguatePlatformConfigurationsToFallBackToMetadataForLenientKmpResolutionUsage::class.java)
+ }
+ dependencies.attributesSchema.attribute(KotlinPlatformType.attribute) { strategy ->
+ strategy.compatibilityRules.add(AllowPlatformConfigurationsToFallBackToMetadataForLenientKmpResolution::class.java)
+ }
+ with(dependencies.artifactTypes.getByName("jar").attributes) {
+ setAttribute(isMetadataJar, isMetadataJarUnknown)
+ }
+ dependencies.registerTransform(ThrowAwayMetadataJarsTransform::class.java) {
+ it.from.setAttribute(isMetadataJar, isMetadataJarUnknown)
+ it.to.setAttribute(isMetadataJar, notMetadataJar)
+ it.parameters.fakeUklibUnzip.set(kotlinPropertiesProvider.fakeUkibTransforms)
+ }
+ targets.configureEach {
+ if (it is KotlinNativeTarget || it is KotlinJsIrTarget || it is KotlinJvmTarget
+ // || it is KotlinAndroidTarget
+ ) {
+ it.compilations.configureEach {
+ listOfNotNull(
+ it.internal.configurations.compileDependencyConfiguration,
+ it.internal.configurations.runtimeDependencyConfiguration,
+ ).forEach {
+ with(it.attributes) {
+ setAttribute(isMetadataJar, notMetadataJar)
+ }
+ }
+ }
+ }
+ }
+}
+
+private class AllowPlatformConfigurationsToFallBackToMetadataForLenientKmpResolution : AttributeCompatibilityRule<KotlinPlatformType> {
+ override fun execute(details: CompatibilityCheckDetails<KotlinPlatformType>) = with(details) {
+ consumerValue?.name ?: return@with
+ val producer = producerValue?.name ?: return@with
+ if (producer == KotlinPlatformType.common.name) compatible()
+ }
+}
+
+private class AllowPlatformConfigurationsToFallBackToMetadataForLenientKmpResolutionUsage : AttributeCompatibilityRule<Usage> {
+ override fun execute(details: CompatibilityCheckDetails<Usage>) = with(details) {
+ val consumerUsage = consumerValue?.name ?: return@with
+ val producerUsage = producerValue?.name ?: return@with
+ if (
+ mapOf(
+ // Platform compile dependency configuration
+ KOTLIN_UKLIB_API to setOf(
+ // Allow uklib consumer to resolve regular KMP platform apiElements. The exact selection is still controlled with other attributes
+ KOTLIN_API,
+ // FIXME: Allow selecting java-only? Test this
+ JAVA_API,
+ // Fallback to metadata variant to inherit dependencies like in uklib publication
+ // stdlib doesn't have native variants, so for native platform configuration must fall back here
+ // runtime also???
+ KOTLIN_METADATA
+ ),
+ // FIXME: Test these
+ KOTLIN_UKLIB_RUNTIME to setOf(KOTLIN_API, KOTLIN_RUNTIME, JAVA_RUNTIME),
+
+ // but dom-api-compat has compatibility variant, but the usage is wrong, what???
+ KOTLIN_METADATA to setOf(KOTLIN_API),
+ )[consumerUsage]?.contains(producerUsage) == true
+ ) compatible()
+ }
+}
+
+private class DisambiguatePlatformConfigurationsToFallBackToMetadataForLenientKmpResolutionUsage : AttributeDisambiguationRule<Usage> {
+ override fun execute(details: MultipleCandidatesDetails<Usage>) = details.run {
+ val consumerUsage = consumerValue?.name ?: return@run
+
+ mapOf(
+ KOTLIN_UKLIB_API to listOf(
+ // We are selecting for platform compilation. Prefer platform apiElements if it is available
+ KOTLIN_API,
+ // FIXME: Check if this is correct
+ JAVA_API,
+ // Fallback to metadata if platform apiElements is not available. In GMT this selection is filtered to determine visibility
+ KOTLIN_METADATA
+ ),
+ KOTLIN_UKLIB_RUNTIME to listOf(KOTLIN_RUNTIME, KOTLIN_API, JAVA_RUNTIME, JAVA_API, KOTLIN_METADATA),
+ )[consumerUsage]?.let {
+ closestMatchToFirstAppropriateCandidate(it)
+ }
+ return@run
+ }
+
+ private fun MultipleCandidatesDetails<Usage>.closestMatchToFirstAppropriateCandidate(acceptedProducerValues: List<String>) {
+ val candidatesMap = candidateValues.associateBy { it.name }
+ acceptedProducerValues.firstOrNull { it in candidatesMap }?.let { closestMatch(candidatesMap.getValue(it)) }
+ }
+}
+
+private val isMetadataJar = Attribute.of("org.jetbrains.kotlin.isMetadataJar", String::class.java)
+internal val isMetadataJarUnknown = "unknown"
+internal val notMetadataJar = "non-a-metadata-jar"
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibResolutionStrategy.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibResolutionStrategy.kt
deleted file mode 100644
index 5a98508..0000000
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibResolutionStrategy.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption
-
-internal enum class UklibResolutionStrategy {
- ResolveUklibsInMavenComponents,
- IgnoreUklibs;
-
- val propertyName: String
- get() = when (this) {
- ResolveUklibsInMavenComponents -> "resolveUklibsInMavenComponents"
- IgnoreUklibs -> "ignoreUklibs"
- }
-
- companion object {
- fun fromProperty(name: String): UklibResolutionStrategy? = when (name) {
- ResolveUklibsInMavenComponents.propertyName -> ResolveUklibsInMavenComponents
- IgnoreUklibs.propertyName -> IgnoreUklibs
- else -> null
- }
- }
-}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UnzippedUklibToPlatformCompilationTransform.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UnzippedUklibToPlatformCompilationTransform.kt
index 4106dbd..5ab84c0 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UnzippedUklibToPlatformCompilationTransform.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UnzippedUklibToPlatformCompilationTransform.kt
@@ -58,17 +58,20 @@
*
* Should we check this case and silently ignore this case here by detecting that the file is not present?
*/
- throw PlatformCompilationTransformException(
- unzippedUklib,
- targetFragmentAttribute,
- uklib.module.fragments.map { it.identifier }.sorted()
- )
+ // FIXME: 02.02.2025 - Now we no longer need this
+// throw PlatformCompilationTransformException(
+// unzippedUklib,
+// targetFragmentAttribute,
+// uklib.module.fragments.map { it.identifier }.sorted()
+// )
}
if (platformFragments.size > 1) {
error("Matched multiple fragments from ${unzippedUklib}, but was expecting to find exactly one. Found fragments: $platformFragments")
}
- outputs.dir(platformFragments.single().file())
+ platformFragments.singleOrNull()?.let {
+ outputs.dir(it.file())
+ }
}
}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/uklibTransformationAttributes.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/uklibTransformationAttributes.kt
index 3414c72..4f7eaff 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/uklibTransformationAttributes.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/uklibTransformationAttributes.kt
@@ -8,6 +8,7 @@
import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeContainer
+import org.gradle.api.attributes.Usage
// Means this is uklib itself of a platform fragment transformed from the uklib
internal val ResolvedArtifactResult.isFromUklib: Boolean
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/diagnostics/UklibFromKGPSourceSetsDependenciesChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/diagnostics/UklibFromKGPSourceSetsDependenciesChecker.kt
index 49cd454..adc2135 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/diagnostics/UklibFromKGPSourceSetsDependenciesChecker.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/diagnostics/UklibFromKGPSourceSetsDependenciesChecker.kt
@@ -40,6 +40,9 @@
fun Configuration.declaredDependencies() = incoming.dependencies.filterNot {
it.group == KOTLIN_MODULE_GROUP && it.name in ignoreDependenciesInsertedByDefault
+ }.filterNot {
+ false
+// it is NpmDependency ???
}.toSet()
val compilationDependencies = uklibPublishedPlatformCompilations.associate {
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/ArchiveUklibTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/ArchiveUklibTask.kt
index 7672849..b5a453f 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/ArchiveUklibTask.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/ArchiveUklibTask.kt
@@ -28,11 +28,13 @@
@get:OutputFile
val outputZip: RegularFileProperty = project.objects.fileProperty().convention(
+ // fixme: use convention name + output locations
project.layout.buildDirectory.file("library.${Uklib.UKLIB_EXTENSION}")
)
@get:Internal
val temporariesDirectory: DirectoryProperty = project.objects.directoryProperty().convention(
+ // fixme: use streams instead tmp files
project.layout.buildDirectory.dir("uklibTemp")
)
@@ -56,6 +58,11 @@
*/
val compiledFragments = this.fragmentsWithTransitiveRefinees.get().filterKeys { fragment ->
val isMetadata = fragment.attributes.count() > 1
+ // write code in nativeMain
+ // compile
+ // realize that all nativeMain can be moved to commonMain. Move it
+ // compile again
+ // all good and nice, publish it!
if (isMetadata && !fragment.file().exists()) {
return@filterKeys false
}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/UklibFromKGPModel.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/UklibFromKGPModel.kt
index a793c32..6e88ea4 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/UklibFromKGPModel.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/UklibFromKGPModel.kt
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.publication
import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
@@ -36,6 +37,7 @@
val refineesTransitiveClosure: Set<String>,
val providingTask: TaskProvider<*>,
val outputFile: Provider<File>,
+ val compilation: KotlinCompilation<*>,
)
internal suspend fun KotlinMultiplatformExtension.validateKgpModelIsUklibCompliantAndCreateKgpFragments(): List<KGPUklibFragment> {
@@ -70,6 +72,7 @@
fragments.add(kgpUklibFragment(mainCompilation, jarTask, jarArtifact))
}
else -> {
+
when (val attribute = target.uklibFragmentPlatformAttribute) {
is UklibFragmentPlatformAttribute.PublishAndConsumeInMetadataCompilations -> { /* Do nothing for AGP */ }
is UklibFragmentPlatformAttribute.PublishAndConsumeInAllCompilations -> { error("Unexpected") }
@@ -87,11 +90,22 @@
return emptyList()
}
+ // On Linux Host (iosMain is not publishable)
+ //
+ // Metadata Compilation:
+ // P = Publishable compilations/default source sets on Platform Targets -> (jvmMain, iosX64Main, ...) NO TEST!
+ // for each intermediate source set all targets should be part of P
+ // commonTest -> jvmTest, iosX64Test, ...
+ //
+ // Metadata compilations are ALL ABOUT PUBLICATION!!!! to teach consumer's IDEs to see intermediate source sets!
+ //
+
val publishedMetadataCompilations = awaitMetadataTarget().publishedMetadataCompilations()
publishedMetadataCompilations.forEach { metadataCompilation ->
val artifact = metadataCompilation.project.provider {
metadataCompilation.metadataPublishedArtifacts.singleFile
}
+ // FIXME: Remove this
unsupportedTargets.addAll(
metadataCompilation.metadataFragmentAttributes.filterIsInstance<UklibFragmentPlatformAttribute.FailOnPublicationAndUseTargetNameForMetadataCompilations>().map {
it.unsupportedTargetName
@@ -112,6 +126,7 @@
refineesTransitiveClosure = metadataCompilation.refineesTransitiveClosure(),
providingTask = metadataCompilation.compileTaskProvider,
outputFile = artifact,
+ compilation = metadataCompilation,
)
)
}
@@ -176,6 +191,7 @@
refineesTransitiveClosure = mainCompilation.refineesTransitiveClosure(),
providingTask = artifactProvidingTask,
outputFile = file,
+ compilation = mainCompilation,
)
private fun KotlinCompilation<*>.refineesTransitiveClosure(): Set<String> = internal.allKotlinSourceSets
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/UklibPomDependenciesRewriter.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/UklibPomDependenciesRewriter.kt
index 926a448..f7629ec 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/UklibPomDependenciesRewriter.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/UklibPomDependenciesRewriter.kt
@@ -40,6 +40,7 @@
// Leave if it's already compile
if (scope?.text() == "compile") return@forEach
+ // FIXME: Drop this and rewrite everything to compile
scopeMapping[DependencyGA(group, artifact)]?.let {
when (it) {
KotlinUsageContext.MavenScope.COMPILE -> scope?.setValue("compile")
@@ -81,7 +82,7 @@
}
}.forEach { set ->
set.dependencySet.forEach { dependency ->
- val dep = DependencyGA(dependency.group, dependency.name)
+ val dep = DependencyGA(dependency.group, dependency.name) // mavenPublication {customArtifact = "custom" group = "custom" }
val exScope = dependencyRemapping[dep]
when (exScope) {
KotlinUsageContext.MavenScope.COMPILE -> {}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/locateOrRegisterArchiveUklibTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/locateOrRegisterArchiveUklibTask.kt
index d506e3d..0446ce7 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/locateOrRegisterArchiveUklibTask.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/publication/locateOrRegisterArchiveUklibTask.kt
@@ -6,16 +6,27 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.publication
import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.attributes.Category
+import org.gradle.api.attributes.Usage
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
+import org.jetbrains.kotlin.gradle.dsl.awaitMetadataTarget
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
+import org.jetbrains.kotlin.gradle.plugin.categoryByName
+import org.jetbrains.kotlin.gradle.plugin.mpp.*
+import org.jetbrains.kotlin.gradle.plugin.mpp.internal
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.Uklib
+import org.jetbrains.kotlin.gradle.plugin.usageByName
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
import org.jetbrains.kotlin.gradle.tasks.locateTask
+import org.jetbrains.kotlin.gradle.utils.createConsumable
-internal suspend fun Project.locateOrRegisterArchiveUklibTask(): TaskProvider<ArchiveUklibTask> {
+
+internal suspend fun Project.createUklibPublication(): List<DefaultKotlinUsageContext> {
val taskName = "archiveUklib"
- tasks.locateTask<ArchiveUklibTask>(taskName)?.let { return it }
-
val archiveUklib = tasks.register(taskName, ArchiveUklibTask::class.java)
val kgpFragments = multiplatformExtension.validateKgpModelIsUklibCompliantAndCreateKgpFragments()
@@ -37,7 +48,123 @@
)
}
- return archiveUklib
+ return setupOutgoingUklibConfigurations(
+ archiveUklib,
+ kgpFragments
+ )
+}
+
+internal suspend fun Project.setupOutgoingUklibConfigurations(
+ archiveTask: TaskProvider<ArchiveUklibTask>,
+ publishedCompilations: List<KGPUklibFragment>,
+): List<DefaultKotlinUsageContext> {
+ val uklibApiElements = "uklibApiElements"
+ val uklibRuntimeElements = "uklibRuntimeElements"
+
+ configurations.createConsumable(uklibApiElements) {
+ attributes.apply {
+ attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_UKLIB_API))
+ attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
+ }
+ publishedCompilations.forEach {
+ extendsFrom(
+ it.compilation.internal.configurations.apiConfiguration
+ )
+ if (it.compilation is KotlinNativeCompilation) {
+ extendsFrom(it.compilation.internal.configurations.implementationConfiguration)
+ }
+ }
+ }
+ configurations.createConsumable(uklibRuntimeElements) {
+ attributes.apply {
+ attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_UKLIB_RUNTIME))
+ attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
+ }
+ publishedCompilations.forEach {
+ it.compilation.internal.configurations.runtimeDependencyConfiguration?.let {
+ extendsFrom(it)
+ }
+ }
+ }
+
+ project.artifacts.add(uklibApiElements, archiveTask) {
+ it.extension = Uklib.UKLIB_EXTENSION
+ }
+ project.artifacts.add(uklibRuntimeElements, archiveTask) {
+ it.extension = Uklib.UKLIB_EXTENSION
+ }
+
+ KotlinPluginLifecycle.Stage.AfterFinaliseCompilations.await()
+ val metadataTarget = multiplatformExtension.awaitMetadataTarget()
+ val variants = mutableListOf(
+ DefaultKotlinUsageContext(
+ // Whatever, this compilation doesn't matter
+ compilation = metadataTarget.compilations.getByName("main"),
+ dependencyConfigurationName = uklibRuntimeElements,
+ includeIntoProjectStructureMetadata = false,
+ ),
+ DefaultKotlinUsageContext(
+ // Whatever, this compilation doesn't matter
+ compilation = metadataTarget.compilations.getByName("main"),
+ dependencyConfigurationName = uklibApiElements,
+ includeIntoProjectStructureMetadata = false,
+ )
+ )
+
+ val jar = locateOrStubJvmJarTask()
+ val jvmApiElements = "uklib-jvmApiElements"
+ val jvmRuntimeElements = "uklib-jvmRuntimeElements"
+ configurations.createConsumable(jvmApiElements) {
+ attributes.apply {
+ attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(Usage.JAVA_API))
+ attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
+ }
+ publishedCompilations.forEach {
+ extendsFrom(
+ it.compilation.internal.configurations.apiConfiguration
+ )
+ if (it.compilation is KotlinNativeCompilation) {
+ extendsFrom(it.compilation.internal.configurations.implementationConfiguration)
+ }
+ }
+ }
+ configurations.createConsumable(jvmRuntimeElements) {
+ attributes.apply {
+ attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(Usage.JAVA_RUNTIME))
+ attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
+ }
+ publishedCompilations.forEach {
+ it.compilation.internal.configurations.runtimeDependencyConfiguration?.let {
+ extendsFrom(it)
+ }
+ }
+ }
+ project.artifacts.add(jvmApiElements, jar) {
+ it.extension = "jar"
+ }
+ project.artifacts.add(jvmRuntimeElements, jar) {
+ it.extension = "jar"
+ }
+
+ val jvmComp: KotlinCompilation<*> = publishedCompilations.singleOrNull {
+ it.compilation is KotlinJvmCompilation
+ }?.compilation ?: metadataTarget.compilations.getByName("main")
+ variants.addAll(
+ listOf(
+ DefaultKotlinUsageContext(
+ compilation = jvmComp,
+ dependencyConfigurationName = jvmApiElements,
+ includeIntoProjectStructureMetadata = false,
+ ),
+ DefaultKotlinUsageContext(
+ compilation = jvmComp,
+ dependencyConfigurationName = jvmRuntimeElements,
+ includeIntoProjectStructureMetadata = false,
+ ),
+ )
+ )
+
+ return variants
}
internal suspend fun Project.locateOrStubJvmJarTask(): TaskProvider<Jar> {
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFusService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFusService.kt
index b1b2674..c527cf4 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFusService.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFusService.kt
@@ -85,8 +85,8 @@
registerIfAbsentImpl(project, pluginVersion, buildUidService).also { serviceProvider ->
SingleActionPerProject.run(project, UsesBuildFusService::class.java.name) {
project.tasks.withType<UsesBuildFusService>().configureEach { task ->
- task.buildFusService.value(serviceProvider).disallowChanges()
- task.usesService(serviceProvider)
+// task.buildFusService.value(serviceProvider).disallowChanges()
+// task.usesService(serviceProvider)
}
}
}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/FlowActionBuildFusService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/FlowActionBuildFusService.kt
index 58b1187..1715201 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/FlowActionBuildFusService.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/FlowActionBuildFusService.kt
@@ -59,7 +59,7 @@
fun getConfigurationTimeMetrics(): Provider<List<MetricContainer>> {
return providerFactory.provider {
synchronized(this) {
- configurationMetrics.disallowChanges()
+// configurationMetrics.disallowChanges()
configurationMetrics.get()
}
}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt
index 6b47b15..85809ff 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt
@@ -157,6 +157,7 @@
* source set.
* See also: [buildKotlinProjectStructureMetadata], where these dependencies must be included into the source set exported deps.
*/
+ // FIXME: Maybe tie this to the uklib apiElements configuration
if (isSharedNativeCompilation) {
sourceSet.internal.withDependsOnClosure.forEach { hierarchySourceSet ->
apiElementsConfiguration.extendsFrom(
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/PP.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/PP.kt
new file mode 100644
index 0000000..d17d943
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/PP.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.unitTests.uklibs
+
+import kotlin.reflect.full.memberProperties
+import kotlin.test.assertEquals
+
+class PP(
+ val value: Any,
+ val indentation: Int,
+) {
+ override fun toString(): String {
+ val twoSpaces = " ".repeat(2)
+ val indentationSpace = " ".repeat(indentation)
+ val nextIndentationDepth = indentation + 2
+ val elements: Array<String> = when (value) {
+ is Map<*, *> -> arrayOf(
+ "mutableMapOf(",
+ *value.map { it }.sortedBy { it.key.toString() }.map {
+ "${twoSpaces}${it.key?.pp()} to ${it.value?.pp(nextIndentationDepth)},"
+ }.toTypedArray(),
+ ")",
+ )
+ is Iterable<*> -> {
+ val innerValue = value.map { "${twoSpaces}${it?.pp(nextIndentationDepth)}," }.toTypedArray()
+ when (value) {
+ is Set<*> -> arrayOf(
+ "mutableSetOf(",
+ *innerValue,
+ ")",
+ )
+ is List<*> -> arrayOf(
+ "mutableListOf(",
+ *innerValue,
+ ")",
+ )
+ else -> arrayOf(
+ "mutableListOf(",
+ *innerValue,
+ ")",
+ )
+ }
+ }
+ else -> {
+ val packageName = value::class.java.packageName
+ if (packageName.startsWith("kotlin.") || packageName.startsWith("java.")) {
+ if (value is String) {
+ arrayOf("\"${value}\"")
+ } else {
+ arrayOf(value.toString())
+ }
+ } else {
+ val kClass = value::class
+ arrayOf(
+ "${kClass.simpleName}(",
+ *kClass.memberProperties.map { prop ->
+ "${twoSpaces}${prop.name} = ${prop.getter.call(value)?.pp(nextIndentationDepth)},"
+ }.toTypedArray(),
+ ")",
+ )
+ }
+ }
+ }
+
+ if (elements.size == 1) return elements[0]
+
+ return (listOf(elements[0]) + elements.toList().subList(1, elements.size).map { "${indentationSpace}${it}" }).joinToString("\n")
+ }
+
+ override fun hashCode(): Int {
+ return value.hashCode()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ var otherUnwrapped = other
+ if (other is PP) otherUnwrapped = other.value
+ return value.equals(otherUnwrapped)
+ }
+}
+
+fun Any.pp(indentation: Int = 0): PP = PP(this, indentation)
+
+fun <T> assertEqualsPP(expected: T, actual: T) {
+// if (expected != actual) {
+// println(actual?.pp())
+// }
+ assertEquals((expected as Any).pp(), (actual as Any).pp())
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/PPTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/PPTest.kt
new file mode 100644
index 0000000..e04fb09
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/PPTest.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.unitTests.uklibs
+
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class PPTest {
+
+ @Test
+ fun test() {
+ val immutable: Any = listOf("a")
+ val mutable: Any = mutableListOf("m")
+
+ fun foo(value: Any) {
+ when (value) {
+ is MutableList<*> -> {
+ }
+ is List<*> -> {
+ println("List: ${value}, ${value.javaClass}, ${List::class.java.isInstance(value)}")
+ }
+ }
+ }
+
+ foo(mutable)
+ foo(immutable)
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTesting.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTesting.kt
new file mode 100644
index 0000000..d54ac43
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTesting.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.unitTests.uklibs
+
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.attributes.Attribute
+import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
+import org.jetbrains.kotlin.gradle.plugin.mpp.internal
+import org.jetbrains.kotlin.gradle.utils.projectPathOrNull
+
+data class ResolvedComponentWithArtifacts(
+ val configuration: String,
+ val artifacts: MutableList<Map<String, String>> = mutableListOf(),
+) : java.io.Serializable
+
+fun Configuration.resolveProjectDependencyComponentsWithArtifacts(): Map<String, ResolvedComponentWithArtifacts> {
+ val artifacts = resolveProjectDependencyVariantsFromArtifacts().filterNot { it.path == ":" }
+ val components = resolveProjectDependencyComponents().filterNot { it.path == ":" }
+ val componentToArtifacts = LinkedHashMap<String, ResolvedComponentWithArtifacts>()
+ components.forEach { component ->
+ if (componentToArtifacts[component.path] == null) {
+ componentToArtifacts[component.path] = ResolvedComponentWithArtifacts(component.configuration)
+ } else {
+ error("${component} resolved multiple times?")
+ }
+ }
+ artifacts.forEach { artifact ->
+ componentToArtifacts[artifact.path]?.let {
+ it.artifacts.add(artifact.attributes)
+ } ?: error("Missing resolved component for artifact: ${artifact}")
+ }
+ return componentToArtifacts
+}
+
+fun KotlinTarget.compilationResolution(compilationName: String = "main") = compilations
+ .getByName(compilationName).internal.configurations.compileDependencyConfiguration
+ .resolveProjectDependencyComponentsWithArtifacts()
+
+private data class ResolvedVariant(
+ val path: String,
+ val attributes: Map<String, String>,
+)
+
+private data class ResolvedComponent(
+ val path: String,
+ val configuration: String,
+)
+
+private fun Configuration.resolveProjectDependencyVariantsFromArtifacts(): List<ResolvedVariant> {
+ return incoming.artifacts.artifacts
+ .map { artifact ->
+ val uklibAttributes: List<Attribute<*>> = artifact.variant.attributes.keySet()
+ .sortedBy { it.name }
+ ResolvedVariant(
+ artifact.variant.owner.projectPathOrNull ?: artifact.variant.owner.displayName,
+ uklibAttributes.associateBy({ it }) {
+ artifact.variant.attributes.getAttribute(it).toString()
+ }.mapKeys { it.key.name }
+ )
+ }
+}
+
+private fun Configuration.resolveProjectDependencyComponents(): List<ResolvedComponent> {
+ return incoming.resolutionResult.allComponents
+ .map { component ->
+ ResolvedComponent(
+ component.id.projectPathOrNull ?: component.id.displayName,
+ // Expect a single variant to always be selected?
+ component.variants.single().displayName
+ )
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTestingAttributes.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTestingAttributes.kt
new file mode 100644
index 0000000..7a322c5
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTestingAttributes.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.unitTests.uklibs
+
+val uklibTransformationIosArm64Attributes = mapOf(
+ "artifactType" to "uklib",
+ "org.jetbrains.kotlin.uklibView" to "ios_arm64",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+)
+val uklibTransformationJvmAttributes = mapOf(
+ "artifactType" to "uklib",
+ "org.jetbrains.kotlin.uklibView" to "jvm",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+)
+val uklibTransformationMetadataAttributes = mapOf(
+ "artifactType" to "uklib",
+ "org.jetbrains.kotlin.uklibView" to "whole_uklib",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+)
+val uklibTransformationJsAttributes = mapOf(
+ "artifactType" to "uklib",
+ "org.jetbrains.kotlin.uklibView" to "js_ir",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+)
+val uklibTransformationWasmJsAttributes = mapOf(
+ "artifactType" to "uklib",
+ "org.jetbrains.kotlin.uklibView" to "wasm_js",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+)
+val uklibTransformationWasmWasiAttributes = mapOf(
+ "artifactType" to "uklib",
+ "org.jetbrains.kotlin.uklibView" to "wasm_wasi",
+ "org.jetbrains.kotlin.uklibState" to "decompressed",
+)
+val uklibVariantAttributes = mapOf(
+ "org.gradle.category" to "library",
+ "org.gradle.usage" to "kotlin-uklib-api",
+)
+val jvmRuntimeAttributes = mapOf(
+ "org.gradle.category" to "library",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "java-runtime",
+)
+val jvmApiAttributes = mapOf(
+ "org.gradle.category" to "library",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.status" to "release",
+ "org.gradle.usage" to "java-api",
+)
+val kmpJvmRuntimeVariantAttributes = mapOf(
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "standard-jvm",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.usage" to "java-runtime",
+ "org.jetbrains.kotlin.platform.type" to "jvm",
+)
+val kmpJvmApiVariantAttributes = mapOf(
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "standard-jvm",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.usage" to "java-api",
+ "org.jetbrains.kotlin.platform.type" to "jvm",
+)
+val kmpMetadataVariantAttributes = mapOf(
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "non-jvm",
+ "org.gradle.libraryelements" to "jar",
+ "org.gradle.usage" to "kotlin-metadata",
+ "org.jetbrains.kotlin.platform.type" to "common",
+)
+val releaseStatus = mapOf(
+ "org.gradle.status" to "release",
+)
+
+// We only emit packing in secondary variants which are not published?
+val nonPacked = mapOf(
+ "org.jetbrains.kotlin.klib.packaging" to "non-packed",
+)
+val jarArtifact = mapOf(
+ "artifactType" to "jar",
+)
+val uklibArtifact = mapOf(
+ "artifactType" to "uklib",
+)
+val platformIosArm64Attributes = mapOf(
+ "artifactType" to "org.jetbrains.kotlin.klib",
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "non-jvm",
+ "org.gradle.usage" to "kotlin-api",
+ "org.jetbrains.kotlin.cinteropCommonizerArtifactType" to "klib",
+ "org.jetbrains.kotlin.native.target" to "ios_arm64",
+ "org.jetbrains.kotlin.platform.type" to "native",
+)
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibDependencyDeclarationViolations.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibDependencyDeclarationViolations.kt
index 13b6a50..6ac4ae9 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibDependencyDeclarationViolations.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibDependencyDeclarationViolations.kt
@@ -176,6 +176,95 @@
}
}
+ @Test
+ fun `dependency specification validation - different compilation scopes - don't trigger violation`() {
+ runTest(
+ { emptySet() }
+ ) {
+ jvm()
+ js()
+
+ // Scopes don't matter because we only care about that all compilations see the same set of dependencies
+ sourceSets.commonMain.dependencies {
+ implementation("a:common:1.0")
+ }
+ sourceSets.jvmMain.dependencies {
+ compileOnly("a:common:1.0")
+ }
+ sourceSets.jsMain.dependencies {
+ api("a:common:1.0")
+ }
+ }
+ }
+
+ @Test
+ fun `dependency specification validation - runtime scope - isn't validated`() {
+ runTest(
+ { emptySet() }
+ ) {
+ jvm()
+ js()
+
+ // We probably don't care about runtime dependencies, so those can be whatever
+ sourceSets.commonMain.dependencies {
+ implementation("a:common:1.0")
+ }
+ sourceSets.jvmMain.dependencies {
+ runtimeOnly("a:runtime_only:1.0")
+ }
+ }
+ }
+
+ @Test
+ fun `dependency specification validation - test compilation dependencies - are not validated`() {
+ runTest(
+ { emptySet() }
+ ) {
+ jvm()
+ js()
+
+ // We don't validate test compilations at all
+ sourceSets.commonMain.dependencies {
+ implementation("a:common:1.0")
+ }
+ sourceSets.commonTest.dependencies {
+ implementation("a:common_test:1.0")
+ }
+ sourceSets.jvmTest.dependencies {
+ implementation("a:jvm_test:1.0")
+ }
+ }
+ }
+
+ @Test
+ fun `dependency specification validation - npm dependencies`() {
+ runTest(
+ { emptySet() }
+ ) {
+ jvm()
+ js()
+
+ sourceSets.jsMain.dependencies {
+ implementation(npm("mocha", "*"))
+ }
+ }
+ }
+
+ @Test
+ fun `dependency specification validation - stdlib and dom dependencies - are not validated`() {
+ runTest(
+ { emptySet() }
+ ) {
+ jvm()
+ js()
+
+ sourceSets.jsMain.dependencies {
+ implementation("")
+ }
+ }
+ }
+
+
private fun violation(
configuration: Configuration,
uniqueDependencies: Set<Dependency>,
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibFromKGPFragmentsTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibFromKGPFragmentsTests.kt
index d2508f6..0314ab1 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibFromKGPFragmentsTests.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibFromKGPFragmentsTests.kt
@@ -11,8 +11,10 @@
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.ERROR
import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.WARNING
+import org.jetbrains.kotlin.gradle.plugin.mpp.InternalKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.external.createCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.external.createExternalKotlinTarget
+import org.jetbrains.kotlin.gradle.plugin.mpp.internal
import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.UklibFragment
import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.publication.validateKgpModelIsUklibCompliantAndCreateKgpFragments
import org.jetbrains.kotlin.gradle.util.*
@@ -282,6 +284,58 @@
}.evaluate().assertNoDiagnostics()
}
+ @Test
+ fun `project configuration with enabled uklib publication - source set dependencies`() {
+ val p = buildProjectWithMPP(
+ preApplyCode = {
+ publishUklib()
+ }
+ ) {
+ kotlin {
+ sourceSets.commonMain.get().dependencies {
+ implementation("foo:bar:1")
+ }
+ iosArm64()
+ }
+ }.evaluate()
+ println(p)
+// .multiplatformExtension.iosArm64().internal
+// .compilations
+// .getByName("main").internal.configurations.compileDependencyConfiguration.dependencies
+ }
+
+ @Test
+ fun `underrefinmenet`() {
+ val p = buildProjectWithMPP(
+ preApplyCode = {
+ publishUklib()
+ }
+ ) {
+ kotlin {
+ iosArm64()
+ iosX64()
+ jvm()
+
+ applyHierarchyTemplate {
+ group("iosAndJvm") {
+ withIosArm64()
+ withIosX64()
+ withJvm()
+ }
+ group("onlyIos") {
+ withIosArm64()
+ withIosX64()
+ }
+ }
+ }
+
+ }.evaluate()
+ println(p)
+// .multiplatformExtension.iosArm64().internal
+// .compilations
+// .getByName("main").internal.configurations.compileDependencyConfiguration.dependencies
+ }
+
private data class TestFragment(
val identifier: String,
// FIXME: Test transitive refinees
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionTests.kt
index 933dac5..e35cf16 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionTests.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionTests.kt
@@ -6,18 +6,14 @@
package org.jetbrains.kotlin.gradle.unitTests.uklibs
import org.gradle.api.Project
-import org.gradle.api.artifacts.Configuration
-import org.gradle.api.attributes.Attribute
import org.gradle.kotlin.dsl.maven
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
-import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.UklibResolutionStrategy
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.KmpResolutionStrategy
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.util.*
-import org.jetbrains.kotlin.gradle.utils.projectPathOrNull
-import org.jetbrains.kotlin.utils.keysToMap
import kotlin.test.Test
import kotlin.test.assertEquals
@@ -26,7 +22,7 @@
@Test
fun `uklib resolution - from direct pom dependency with uklib packaging`() {
- val consumer = consumer(UklibResolutionStrategy.ResolveUklibsInMavenComponents) {
+ val consumer = consumer(KmpResolutionStrategy.ResolveUklibsAndResolvePSMLeniently) {
jvm()
iosArm64()
iosX64()
@@ -61,7 +57,7 @@
),
"foo.bar:pure-maven-uklib:1.0" to ResolvedComponentWithArtifacts(
configuration="compile",
- artifacts=mutableListOf(jvmPomApiAttributes + uklibTransformationMetadataAttributes)
+ artifacts=mutableListOf(jvmApiAttributes + uklibTransformationMetadataAttributes)
),
),
metadataCompilationVariants
@@ -75,7 +71,7 @@
),
"foo.bar:pure-maven-uklib:1.0" to ResolvedComponentWithArtifacts(
configuration="compile",
- artifacts=mutableListOf(jvmPomApiAttributes + uklibTransformationIosArm64Attributes)
+ artifacts=mutableListOf(jvmApiAttributes + uklibTransformationIosArm64Attributes)
),
),
iosArm64CompilationVariants
@@ -89,7 +85,7 @@
),
"foo.bar:pure-maven-uklib:1.0" to ResolvedComponentWithArtifacts(
configuration="runtime",
- artifacts=mutableListOf(jvmPomRuntimeAttributes + uklibTransformationJvmAttributes)
+ artifacts=mutableListOf(jvmRuntimeAttributes + uklibTransformationJvmAttributes)
),
),
jvmRuntimeVariants
@@ -103,7 +99,7 @@
),
"foo.bar:pure-maven-uklib:1.0" to ResolvedComponentWithArtifacts(
configuration="runtime",
- artifacts=mutableListOf(jvmPomRuntimeAttributes + uklibTransformationJsAttributes)
+ artifacts=mutableListOf(jvmRuntimeAttributes + uklibTransformationJsAttributes)
),
),
jsRuntimeVariants
@@ -117,7 +113,7 @@
),
"foo.bar:pure-maven-uklib:1.0" to ResolvedComponentWithArtifacts(
configuration="runtime",
- artifacts=mutableListOf(jvmPomRuntimeAttributes + uklibTransformationWasmJsAttributes)
+ artifacts=mutableListOf(jvmRuntimeAttributes + uklibTransformationWasmJsAttributes)
),
),
wasmJsVariants
@@ -131,7 +127,7 @@
),
"foo.bar:pure-maven-uklib:1.0" to ResolvedComponentWithArtifacts(
configuration="runtime",
- artifacts=mutableListOf(jvmPomRuntimeAttributes + uklibTransformationWasmWasiAttributes)
+ artifacts=mutableListOf(jvmRuntimeAttributes + uklibTransformationWasmWasiAttributes)
),
),
wasmWasiVariants
@@ -140,7 +136,7 @@
@Test
fun `uklib resolution - from direct pom dependency with uklib packaging points to untrasformed uklib - when uklibs are not allowed to resolve`() {
- val consumer = consumer(UklibResolutionStrategy.IgnoreUklibs) {
+ val consumer = consumer(KmpResolutionStrategy.StandardKMPResolution) {
jvm()
iosArm64()
iosX64()
@@ -174,7 +170,7 @@
),
"foo.bar:pure-maven-uklib:1.0" to ResolvedComponentWithArtifacts(
configuration="compile",
- artifacts=mutableListOf(jvmPomApiAttributes + uklibArtifact)
+ artifacts=mutableListOf(jvmApiAttributes + uklibArtifact)
),
),
metadataCompilationVariants
@@ -188,7 +184,7 @@
),
"foo.bar:pure-maven-uklib:1.0" to ResolvedComponentWithArtifacts(
configuration="compile",
- artifacts=mutableListOf(jvmPomApiAttributes + uklibArtifact)
+ artifacts=mutableListOf(jvmApiAttributes + uklibArtifact)
),
),
iosArm64CompilationVariants
@@ -202,7 +198,7 @@
),
"foo.bar:pure-maven-uklib:1.0" to ResolvedComponentWithArtifacts(
configuration="runtime",
- artifacts=mutableListOf(jvmPomRuntimeAttributes + uklibArtifact)
+ artifacts=mutableListOf(jvmRuntimeAttributes + uklibArtifact)
),
),
jvmRuntimeVariants
@@ -212,7 +208,7 @@
// consumer <- pure jvm <- uklib <- PSM-only
@Test
fun `uklib resolution - from transitive uklib dependency`() {
- val consumer = consumer(UklibResolutionStrategy.ResolveUklibsInMavenComponents) {
+ val consumer = consumer(KmpResolutionStrategy.ResolveUklibsAndResolvePSMLeniently) {
jvm()
iosArm64()
iosX64()
@@ -240,15 +236,15 @@
),
"foo.bar:pure-maven-jvm-with-trasitive-uklib-dependency:1.0" to ResolvedComponentWithArtifacts(
configuration="compile",
- artifacts=mutableListOf(jvmPomApiAttributes + jarArtifact)
+ artifacts=mutableListOf(jvmApiAttributes + jarArtifact)
),
"foo.bar:pure-maven-uklib-with-transitive-non-uklib-dependency:1.0" to ResolvedComponentWithArtifacts(
configuration="compile",
- artifacts=mutableListOf(jvmPomApiAttributes + uklibTransformationMetadataAttributes)
+ artifacts=mutableListOf(jvmApiAttributes + uklibTransformationMetadataAttributes)
),
"foo.bar:uklib-maven-gradle-packaging:1.0" to ResolvedComponentWithArtifacts(
configuration="metadataApiElements",
- artifacts=mutableListOf(metadataVariantAttributes + releaseStatus)
+ artifacts=mutableListOf(kmpMetadataVariantAttributes + releaseStatus)
),
),
metadataCompilationVariants
@@ -262,11 +258,11 @@
),
"foo.bar:pure-maven-jvm-with-trasitive-uklib-dependency:1.0" to ResolvedComponentWithArtifacts(
configuration="runtime",
- artifacts=mutableListOf(jvmPomRuntimeAttributes + jarArtifact)
+ artifacts=mutableListOf(jvmRuntimeAttributes + jarArtifact)
),
"foo.bar:pure-maven-uklib-with-transitive-non-uklib-dependency:1.0" to ResolvedComponentWithArtifacts(
configuration="runtime",
- artifacts=mutableListOf(jvmPomRuntimeAttributes + uklibTransformationJvmAttributes)
+ artifacts=mutableListOf(jvmRuntimeAttributes + uklibTransformationJvmAttributes)
),
"foo.bar:uklib-maven-gradle-packaging:1.0" to ResolvedComponentWithArtifacts(
configuration="jvmRuntimeElements-published",
@@ -274,7 +270,7 @@
),
"foo.bar:uklib-maven-gradle-packaging-jvm:1.0" to ResolvedComponentWithArtifacts(
configuration="jvmRuntimeElements-published",
- artifacts=mutableListOf(platformJvmVariantAttributes + releaseStatus)
+ artifacts=mutableListOf(kmpJvmRuntimeVariantAttributes + releaseStatus)
),
),
jvmRuntimeVariants
@@ -288,11 +284,11 @@
),
"foo.bar:pure-maven-jvm-with-trasitive-uklib-dependency:1.0" to ResolvedComponentWithArtifacts(
configuration="compile",
- artifacts=mutableListOf(jvmPomApiAttributes + jarArtifact)
+ artifacts=mutableListOf(jvmApiAttributes + jarArtifact)
),
"foo.bar:pure-maven-uklib-with-transitive-non-uklib-dependency:1.0" to ResolvedComponentWithArtifacts(
configuration="compile",
- artifacts=mutableListOf(jvmPomApiAttributes + uklibTransformationIosArm64Attributes)
+ artifacts=mutableListOf(jvmApiAttributes + uklibTransformationIosArm64Attributes)
),
"foo.bar:uklib-maven-gradle-packaging:1.0" to ResolvedComponentWithArtifacts(
configuration="iosArm64ApiElements-published",
@@ -327,7 +323,7 @@
}
private fun consumer(
- strategy: UklibResolutionStrategy,
+ strategy: KmpResolutionStrategy,
configure: KotlinMultiplatformExtension.() -> Unit,
): Project {
return buildProjectWithMPP(
@@ -347,167 +343,4 @@
repositories.maven(javaClass.getResource("/dependenciesResolution/UklibTests/repo")!!)
}.evaluate()
}
-
- private val uklibTransformationIosArm64Attributes = mapOf(
- "artifactType" to "uklib",
- "org.jetbrains.kotlin.uklibView" to "ios_arm64",
- "org.jetbrains.kotlin.uklibState" to "decompressed",
- )
-
- private val uklibTransformationJvmAttributes = mapOf(
- "artifactType" to "uklib",
- "org.jetbrains.kotlin.uklibView" to "jvm",
- "org.jetbrains.kotlin.uklibState" to "decompressed",
- )
-
- private val uklibTransformationMetadataAttributes = mapOf(
- "artifactType" to "uklib",
- "org.jetbrains.kotlin.uklibView" to "whole_uklib",
- "org.jetbrains.kotlin.uklibState" to "decompressed",
- )
-
- private val uklibTransformationJsAttributes = mapOf(
- "artifactType" to "uklib",
- "org.jetbrains.kotlin.uklibView" to "js_ir",
- "org.jetbrains.kotlin.uklibState" to "decompressed",
- )
-
- private val uklibTransformationWasmJsAttributes = mapOf(
- "artifactType" to "uklib",
- "org.jetbrains.kotlin.uklibView" to "wasm_js",
- "org.jetbrains.kotlin.uklibState" to "decompressed",
- )
-
- private val uklibTransformationWasmWasiAttributes = mapOf(
- "artifactType" to "uklib",
- "org.jetbrains.kotlin.uklibView" to "wasm_wasi",
- "org.jetbrains.kotlin.uklibState" to "decompressed",
- )
-
- private val uklibVariantAttributes = mapOf(
- "org.gradle.category" to "library",
- "org.gradle.jvm.environment" to "???",
- "org.gradle.usage" to "kotlin-uklib",
- "org.jetbrains.kotlin.klib.packaging" to "packed",
- "org.jetbrains.kotlin.native.target" to "???",
- "org.jetbrains.kotlin.platform.type" to "unknown",
- )
-
- private val jvmPomRuntimeAttributes = mapOf(
- "org.gradle.category" to "library",
- "org.gradle.libraryelements" to "jar",
- "org.gradle.status" to "release",
- "org.gradle.usage" to "java-runtime",
- )
-
- private val jvmPomApiAttributes = mapOf(
- "org.gradle.category" to "library",
- "org.gradle.libraryelements" to "jar",
- "org.gradle.status" to "release",
- "org.gradle.usage" to "java-api",
- )
-
- private val platformJvmVariantAttributes = mapOf(
- "artifactType" to "jar",
- "org.gradle.category" to "library",
- "org.gradle.jvm.environment" to "standard-jvm",
- "org.gradle.libraryelements" to "jar",
- "org.gradle.usage" to "java-runtime",
- "org.jetbrains.kotlin.platform.type" to "jvm",
- )
-
- private val metadataVariantAttributes = mapOf(
- "artifactType" to "jar",
- "org.gradle.category" to "library",
- "org.gradle.jvm.environment" to "non-jvm",
- "org.gradle.libraryelements" to "jar",
- "org.gradle.usage" to "kotlin-metadata",
- "org.jetbrains.kotlin.platform.type" to "common",
- )
-
- private val releaseStatus = mapOf(
- "org.gradle.status" to "release",
- )
-
- // We only emit packing in secondary variants which are not published?
- private val nonPacked = mapOf(
- "org.jetbrains.kotlin.klib.packaging" to "non-packed",
- )
-
- private val jarArtifact = mapOf(
- "artifactType" to "jar",
- )
-
- private val uklibArtifact = mapOf(
- "artifactType" to "uklib",
- )
-
- private val platformIosArm64Attributes = mapOf(
- "artifactType" to "org.jetbrains.kotlin.klib",
- "org.gradle.category" to "library",
- "org.gradle.jvm.environment" to "non-jvm",
- "org.gradle.usage" to "kotlin-api",
- "org.jetbrains.kotlin.cinteropCommonizerArtifactType" to "klib",
- "org.jetbrains.kotlin.native.target" to "ios_arm64",
- "org.jetbrains.kotlin.platform.type" to "native",
- )
-
- data class ResolvedComponentWithArtifacts(
- val configuration: String,
- val artifacts: MutableList<Map<String, String>> = mutableListOf(),
- )
-
- private fun Configuration.resolveProjectDependencyComponentsWithArtifacts(): Map<String, ResolvedComponentWithArtifacts> {
- val artifacts = resolveProjectDependencyVariantsFromArtifacts()
- val components = resolveProjectDependencyComponents()
- val componentToArtifacts = LinkedHashMap<String, ResolvedComponentWithArtifacts>()
- components.forEach { component ->
- if (componentToArtifacts[component.path] == null) {
- componentToArtifacts[component.path] = ResolvedComponentWithArtifacts(component.configuration)
- } else {
- error("${component} resolved multiple times?")
- }
- }
- artifacts.forEach { artifact ->
- componentToArtifacts[artifact.path]?.let {
- it.artifacts.add(artifact.attributes)
- } ?: error("Missing resolved component for artifact: ${artifact}")
- }
- return componentToArtifacts
- }
-
- data class ResolvedVariant(
- val path: String,
- val attributes: Map<String, String>,
- )
-
- private fun Configuration.resolveProjectDependencyVariantsFromArtifacts(): List<ResolvedVariant> {
- return incoming.artifacts.artifacts
- .map { artifact ->
- val uklibAttributes: List<Attribute<*>> = artifact.variant.attributes.keySet()
- .sortedBy { it.name }
- ResolvedVariant(
- artifact.variant.owner.projectPathOrNull ?: artifact.variant.owner.displayName,
- uklibAttributes.keysToMap {
- artifact.variant.attributes.getAttribute(it).toString()
- }.mapKeys { it.key.name }
- )
- }
- }
-
- data class ResolvedComponent(
- val path: String,
- val configuration: String,
- )
-
- private fun Configuration.resolveProjectDependencyComponents(): List<ResolvedComponent> {
- return incoming.resolutionResult.allComponents
- .map { component ->
- ResolvedComponent(
- component.id.projectPathOrNull ?: component.id.displayName,
- // Expect a single variant to always be selected?
- component.variants.single().displayName
- )
- }
- }
}
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWIPTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWIPTests.kt
new file mode 100644
index 0000000..5d1c9e8
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWIPTests.kt
@@ -0,0 +1,322 @@
+///*
+// * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
+// * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+// */
+//
+//package org.jetbrains.kotlin.gradle.unitTests.uklibs
+//
+//import org.gradle.api.Project
+//import org.jetbrains.kotlin.gradle.artifacts.UklibResolutionStrategy
+//import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
+//import org.jetbrains.kotlin.gradle.unitTests.uklibs.UklibResolutionTests.ResolvedComponentWithArtifacts
+//import org.jetbrains.kotlin.gradle.util.*
+//import org.jetbrains.kotlin.gradle.util.setUklibResolutionStrategy
+//import kotlin.reflect.full.memberProperties
+//import kotlin.test.assertEquals
+//
+//class UklibResolutionWIPTests {
+//
+// // @Test
+// fun `prefer klib variant`() {
+// val consumer = mixedCompilationsGraphConsumer(
+// uklibResolutionStrategy = UklibResolutionStrategy.AllowResolvingUklibs,
+// )
+//
+// val iosArm64CompilationDependencies = consumer.multiplatformExtension.iosArm64().compilations.getByName("main")
+// .configurations.compileDependencyConfiguration
+// val iosArm64ResolvedVariants = iosArm64CompilationDependencies.resolveProjectDependencyComponentsWithArtifacts()
+//
+// val jvmRuntimeDependencies = consumer.multiplatformExtension.jvm().compilations.getByName("main")
+// .configurations.runtimeDependencyConfiguration!!
+// val jvmResolvedVariants = jvmRuntimeDependencies.resolveProjectDependencyComponentsWithArtifacts()
+//
+// assertEquals(
+// mapOf(
+// ":E_consumes_D" to ResolvedComponentWithArtifacts(
+// configuration="jvmRuntimeClasspath",
+// artifacts=mutableListOf()
+// ),
+// ":D_produces_uklib_consumes_C" to ResolvedComponentWithArtifacts(
+// configuration="jvmRuntimeElements",
+// artifacts=mutableListOf(platformJvmVariantAttributes)
+// ),
+// ":C_produces_only_uklib_consumes_B" to ResolvedComponentWithArtifacts(
+// configuration="metadataUklibElements",
+// artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationJvmAttributes)
+// ),
+// ":B_produces_only_platform_variant_consumes_A" to ResolvedComponentWithArtifacts(
+// configuration="jvmRuntimeElements",
+// artifacts=mutableListOf(platformJvmVariantAttributes)
+// ),
+// ":A_produces_uklib" to ResolvedComponentWithArtifacts(
+// configuration="jvmRuntimeElements",
+// artifacts=mutableListOf(platformJvmVariantAttributes),
+// )
+// ),
+// jvmResolvedVariants
+// )
+//
+// assertEquals(
+// mapOf(
+// ":E_consumes_D" to ResolvedComponentWithArtifacts(
+// configuration="iosArm64CompileKlibraries",
+// artifacts=mutableListOf()
+// ),
+// ":D_produces_uklib_consumes_C" to ResolvedComponentWithArtifacts(
+// configuration="iosArm64ApiElements",
+// artifacts=mutableListOf(platformIosArm64Attributes + nonPacked)
+// ),
+// ":C_produces_only_uklib_consumes_B" to ResolvedComponentWithArtifacts(
+// configuration="metadataUklibElements",
+// artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationIosArm64Attributes)
+// ),
+// ":B_produces_only_platform_variant_consumes_A" to ResolvedComponentWithArtifacts(
+// configuration="iosArm64ApiElements",
+// artifacts=mutableListOf(platformIosArm64Attributes + nonPacked)
+// ),
+// ":A_produces_uklib" to ResolvedComponentWithArtifacts(
+// configuration="iosArm64ApiElements",
+// artifacts=mutableListOf(platformIosArm64Attributes + nonPacked),
+// )
+// ),
+// iosArm64ResolvedVariants
+// )
+// }
+//
+// // @Test
+// fun `prefer uklib variant`() {
+// val consumer = mixedCompilationsGraphConsumer(
+// uklibResolutionStrategy = UklibResolutionStrategy.AllowResolvingUklibs,
+// )
+//
+// val iosArm64CompilationDependencies = consumer.multiplatformExtension.iosArm64().compilations.getByName("main")
+// .configurations.compileDependencyConfiguration
+// val iosArm64ResolvedVariants = iosArm64CompilationDependencies.resolveProjectDependencyComponentsWithArtifacts()
+//
+// val jvmRuntimeDependencies = consumer.multiplatformExtension.jvm().compilations.getByName("main")
+// .configurations.runtimeDependencyConfiguration!!
+// // FIXME: java-api variant doesn't resolve A
+// val jvmResolvedVariants = jvmRuntimeDependencies.resolveProjectDependencyComponentsWithArtifacts()
+//
+// assertEquals(
+// mapOf(
+// ":E_consumes_D" to ResolvedComponentWithArtifacts(
+// configuration="jvmRuntimeClasspath",
+// artifacts=mutableListOf()
+// ),
+// ":D_produces_uklib_consumes_C" to ResolvedComponentWithArtifacts(
+// configuration="metadataUklibElements",
+// artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationJvmAttributes)
+// ),
+// ":C_produces_only_uklib_consumes_B" to ResolvedComponentWithArtifacts(
+// configuration="metadataUklibElements",
+// artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationJvmAttributes)
+// ),
+// ":B_produces_only_platform_variant_consumes_A" to ResolvedComponentWithArtifacts(
+// configuration="jvmRuntimeElements",
+// artifacts=mutableListOf(platformJvmVariantAttributes)
+// ),
+// ":A_produces_uklib" to ResolvedComponentWithArtifacts(
+// configuration="metadataUklibElements",
+// artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationJvmAttributes),
+// )
+// ),
+// jvmResolvedVariants
+// )
+//
+// assertEquals(
+// mapOf(
+// ":E_consumes_D" to ResolvedComponentWithArtifacts(
+// configuration="iosArm64CompileKlibraries",
+// artifacts=mutableListOf()
+// ),
+// ":D_produces_uklib_consumes_C" to ResolvedComponentWithArtifacts(
+// configuration="metadataUklibElements",
+// artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationIosArm64Attributes)
+// ),
+// ":C_produces_only_uklib_consumes_B" to ResolvedComponentWithArtifacts(
+// configuration="metadataUklibElements",
+// artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationIosArm64Attributes)
+// ),
+// ":B_produces_only_platform_variant_consumes_A" to ResolvedComponentWithArtifacts(
+// configuration="iosArm64ApiElements",
+// artifacts=mutableListOf(platformIosArm64Attributes + nonPacked)
+// ),
+// ":A_produces_uklib" to ResolvedComponentWithArtifacts(
+// configuration="metadataUklibElements",
+// artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationIosArm64Attributes),
+// )
+// ),
+// iosArm64ResolvedVariants
+// )
+// }
+//
+// private val uklibTransformationIosArm64Attributes = mapOf(
+// "artifactType" to "uklib",
+// "uklibTargetAttribute" to "ios_arm64",
+// "uklibState" to "unzipped",
+// )
+//
+// private val uklibTransformationJvmAttributes = mapOf(
+// "artifactType" to "uklib",
+// "uklibTargetAttribute" to "jvm",
+// "uklibState" to "unzipped",
+// )
+//
+// private val uklibTransformationMetadataAttributes = mapOf(
+// "artifactType" to "uklib",
+// "uklibTargetAttribute" to "common",
+// "uklibState" to "unzipped",
+// )
+//
+// private val uklibTransformationJsAttributes = mapOf(
+// "artifactType" to "uklib",
+// "uklibTargetAttribute" to "js_ir",
+// "uklibState" to "unzipped",
+// )
+//
+// private val uklibTransformationWasmJsAttributes = mapOf(
+// "artifactType" to "uklib",
+// "uklibTargetAttribute" to "wasm_js",
+// "uklibState" to "unzipped",
+// )
+//
+// private val uklibTransformationWasmWasiAttributes = mapOf(
+// "artifactType" to "uklib",
+// "uklibTargetAttribute" to "wasm_wasi",
+// "uklibState" to "unzipped",
+// )
+//
+// private val uklibVariantAttributes = mapOf(
+// "org.gradle.category" to "library",
+// "org.gradle.jvm.environment" to "???",
+// "org.gradle.usage" to "kotlin-uklib",
+// "org.jetbrains.kotlin.klib.packaging" to "packed",
+// "org.jetbrains.kotlin.native.target" to "???",
+// "org.jetbrains.kotlin.platform.type" to "unknown",
+// )
+//
+// private val jvmPomRuntimeAttributes = mapOf(
+// "org.gradle.category" to "library",
+// "org.gradle.libraryelements" to "jar",
+// "org.gradle.status" to "release",
+// "org.gradle.usage" to "java-runtime",
+// )
+//
+// private val jvmPomApiAttributes = mapOf(
+// "org.gradle.category" to "library",
+// "org.gradle.libraryelements" to "jar",
+// "org.gradle.status" to "release",
+// "org.gradle.usage" to "java-api",
+// )
+//
+// private val platformJvmVariantAttributes = mapOf(
+// "artifactType" to "jar",
+// "org.gradle.category" to "library",
+// "org.gradle.jvm.environment" to "standard-jvm",
+// "org.gradle.libraryelements" to "jar",
+// "org.gradle.usage" to "java-runtime",
+// "org.jetbrains.kotlin.platform.type" to "jvm",
+// )
+//
+// private val metadataVariantAttributes = mapOf(
+// "artifactType" to "jar",
+// "org.gradle.category" to "library",
+// "org.gradle.jvm.environment" to "non-jvm",
+// "org.gradle.libraryelements" to "jar",
+// "org.gradle.usage" to "kotlin-metadata",
+// "org.jetbrains.kotlin.platform.type" to "common",
+// )
+//
+// private val releaseStatus = mapOf(
+// "org.gradle.status" to "release",
+// )
+//
+// // We only emit packing in secondary variants which are not published?
+// private val nonPacked = mapOf(
+// "org.jetbrains.kotlin.klib.packaging" to "non-packed",
+// )
+//
+// private val jarArtifact = mapOf(
+// "artifactType" to "jar",
+// )
+//
+// private val uklibArtifact = mapOf(
+// "artifactType" to "uklib",
+// )
+//
+// private val platformIosArm64Attributes = mapOf(
+// "artifactType" to "org.jetbrains.kotlin.klib",
+// "org.gradle.category" to "library",
+// "org.gradle.jvm.environment" to "non-jvm",
+// "org.gradle.usage" to "kotlin-api",
+// "org.jetbrains.kotlin.cinteropCommonizerArtifactType" to "klib",
+// "org.jetbrains.kotlin.native.target" to "ios_arm64",
+// "org.jetbrains.kotlin.platform.type" to "native",
+// )
+//
+//
+// private fun mixedCompilationsGraphConsumer(
+// uklibResolutionStrategy: UklibResolutionStrategy,
+// ): Project {
+// val root = buildProject()
+// return root.child(
+// "E_consumes_D",
+// uklibResolutionStrategy = uklibResolutionStrategy,
+// consume= root.child(
+// "D_produces_uklib_consumes_C",
+// consume = root.child(
+// "C_produces_only_uklib_consumes_B",
+// disablePlatformComponentReferences = true,
+// consume = root.child(
+// "B_produces_only_platform_variant_consumes_A",
+// publishUklibVariant = false,
+// consume = root.child(
+// "A_produces_uklib",
+// consume = null
+// )
+// )
+// )
+// )
+// )
+// }
+//
+// private fun Project.child(
+// name: String,
+// consume: Project?,
+// publishUklibVariant: Boolean = true,
+// disablePlatformComponentReferences: Boolean = false,
+// uklibResolutionStrategy: UklibResolutionStrategy = UklibResolutionStrategy.ResolveOnlyPlatformSpecificVariant,
+// ): Project {
+// val parent = this
+// return buildProjectWithMPP(
+// preApplyCode = {
+// if (publishUklibVariant) {
+// publishUklib()
+// }
+// fakeUklibTransforms()
+// setUklibResolutionStrategy(uklibResolutionStrategy)
+// disablePlatformSpecificComponentReferences(disablePlatformComponentReferences)
+// // Test stdlib in a separate test
+// enableDefaultStdlibDependency(false)
+// enableDefaultJsDomApiDependency(false)
+// },
+// projectBuilder = {
+// withParent(parent)
+// withName(name)
+// }
+// ) {
+// kotlin {
+// iosArm64()
+// iosX64()
+// jvm()
+//
+// if (consume != null) {
+// sourceSets.commonMain.dependencies {
+// implementation(project(consume.project.path))
+// }
+// }
+// }
+// }.evaluate()
+// }
+//}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWithMockComponents.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWithMockComponents.kt
new file mode 100644
index 0000000..23005cf
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWithMockComponents.kt
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.unitTests.uklibs
+
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.maven
+import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
+import org.jetbrains.kotlin.gradle.internal.dsl.KotlinMultiplatformSourceSetConventionsImpl.commonMain
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.KmpResolutionStrategy
+import org.jetbrains.kotlin.gradle.plugin.sources.internal
+import org.jetbrains.kotlin.gradle.unitTests.uklibs.GradleMetadataComponent.Variant
+import org.jetbrains.kotlin.gradle.util.*
+import org.jetbrains.kotlin.gradle.util.setUklibResolutionStrategy
+import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
+import org.junit.Rule
+import org.junit.rules.TemporaryFolder
+import kotlin.test.Test
+
+class UklibResolutionTestsWithMockComponents {
+ @get:Rule
+ val tmpDir = TemporaryFolder()
+
+ @Test
+ fun `uklib resolution - resolving pure uklib component`() {
+ val repo = generateMockRepository(
+ tmpDir,
+ listOf(
+ GradleComponent(
+ GradleMetadataComponent(
+ component = fooBarGradleComponent,
+ variants = listOf(
+ uklibApiVariant,
+ jvmApiVariant,
+ ),
+ ),
+ fooBarUklibMavenComponent,
+ )
+ )
+ )
+
+ val consumer = uklibConsumer {
+ kotlin {
+ iosArm64()
+ jvm()
+ sourceSets.commonMain.dependencies { implementation("foo:bar:1.0") }
+ }
+ repositories.maven(repo)
+ }
+
+ assertEqualsPP(
+ mapOf(
+ "foo:bar:1.0" to ResolvedComponentWithArtifacts(
+ configuration="uklibApiElements",
+ artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationIosArm64Attributes + releaseStatus)
+ ),
+ ),
+ consumer.multiplatformExtension.iosArm64().compilationResolution(),
+ )
+ assertEqualsPP(
+ mapOf(
+ "foo:bar:1.0" to ResolvedComponentWithArtifacts(
+ configuration="uklibApiElements",
+ artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationJvmAttributes + releaseStatus)
+ ),
+ ),
+ consumer.multiplatformExtension.jvm().compilationResolution(),
+ )
+ assertEqualsPP(
+ mapOf(
+ "foo:bar:1.0" to ResolvedComponentWithArtifacts(
+ configuration="uklibApiElements",
+ artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationMetadataAttributes + releaseStatus)
+ ),
+ ),
+ consumer.multiplatformExtension.sourceSets.commonMain.get().internal.resolvableMetadataConfiguration.resolveProjectDependencyComponentsWithArtifacts(),
+ )
+ }
+
+ @Test
+ fun `uklib resolution - resolving existings kmp publication`() {
+ val repo = generateMockRepository(
+ tmpDir,
+ listOf(
+ GradleComponent(
+ GradleMetadataComponent(
+ component = fooBarGradleComponent,
+ variants = listOf(
+ kmpMetadataJarVariant,
+ kmpIosArm64KlibVariant,
+ kmpJvmApiVariant,
+ ),
+ ),
+ fooBarUklibMavenComponent,
+ )
+ )
+ )
+
+ val consumer = uklibConsumer {
+ kotlin {
+ iosArm64()
+ jvm()
+ sourceSets.commonMain.dependencies { implementation("foo:bar:1.0") }
+ }
+ repositories.maven(repo)
+ }
+
+ assertEqualsPP(
+ mapOf(
+ "foo:bar:1.0" to ResolvedComponentWithArtifacts(
+ configuration="uklibApiElements",
+ artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationIosArm64Attributes + releaseStatus)
+ ),
+ ),
+ consumer.multiplatformExtension.iosArm64().compilationResolution(),
+ )
+ assertEqualsPP(
+ mapOf(
+ "foo:bar:1.0" to ResolvedComponentWithArtifacts(
+ configuration="uklibApiElements",
+ artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationJvmAttributes + releaseStatus)
+ ),
+ ),
+ consumer.multiplatformExtension.jvm().compilationResolution(),
+ )
+ assertEqualsPP(
+ mapOf(
+ "foo:bar:1.0" to ResolvedComponentWithArtifacts(
+ configuration="uklibApiElements",
+ artifacts=mutableListOf(uklibVariantAttributes + uklibTransformationMetadataAttributes + releaseStatus)
+ ),
+ ),
+ consumer.multiplatformExtension.sourceSets.commonMain.get().internal.resolvableMetadataConfiguration.resolveProjectDependencyComponentsWithArtifacts(),
+ )
+ }
+
+ private fun uklibConsumer(code: Project.() -> Unit = {}): Project {
+ return buildProjectWithMPP(
+ preApplyCode = {
+ fakeUklibTransforms()
+ setUklibResolutionStrategy(KmpResolutionStrategy.ResolveUklibsAndResolvePSMLeniently)
+ // Test stdlib in a separate test
+ enableDefaultStdlibDependency(false)
+ enableDefaultJsDomApiDependency(false)
+ },
+ code = code,
+ ).evaluate()
+ }
+
+ private val fooBarGradleComponent = GradleMetadataComponent.Component(
+ group = "foo",
+ module = "bar",
+ version = "1.0",
+ )
+ private val fooBarUklibMavenComponent = MavenComponent(
+ "foo", "bar", "1.0",
+ packaging = "uklib",
+ dependencies = listOf(),
+ true,
+ )
+
+ private val uklibApiVariant = Variant(
+ name = "uklibApiElements",
+ attributes = mapOf(
+ "org.gradle.usage" to "kotlin-uklib-api",
+ "org.gradle.category" to "library",
+ ),
+ files = listOf(
+ GradleMetadataComponent.StubVariantFile(
+ artifactId = "bar",
+ version = "1.0",
+ extension = "uklib"
+ )
+ ),
+ dependencies = listOf()
+ )
+
+ private val jvmApiVariant = Variant(
+ name = "jvmApiElements",
+ attributes = jvmApiAttributes,
+ files = listOf(
+ GradleMetadataComponent.StubVariantFile(
+ artifactId = "bar",
+ version = "1.0",
+ extension = "jar"
+ )
+ ),
+ dependencies = listOf()
+ )
+
+ private val aarApiVariant = Variant(
+ name = "jvmApiElements",
+ attributes = jvmApiAttributes,
+ files = listOf(
+ GradleMetadataComponent.StubVariantFile(
+ artifactId = "bar",
+ version = "1.0",
+ extension = "jar"
+ )
+ ),
+ dependencies = listOf()
+ )
+
+ private val kmpMetadataJarVariant = Variant(
+ name = "metadataApiElements",
+ attributes = kmpMetadataVariantAttributes,
+ files = listOf(
+ GradleMetadataComponent.StubVariantFile(
+ artifactId = "bar",
+ version = "1.0",
+ extension = "jar"
+ )
+ ),
+ dependencies = listOf()
+ )
+
+ private val kmpIosArm64KlibVariant = Variant(
+ name = "iosArm64ApiElements-published",
+ attributes = mapOf(
+ "artifactType" to "org.jetbrains.kotlin.klib", // wtf?
+ "org.gradle.category" to "library",
+ "org.gradle.jvm.environment" to "non-jvm",
+ "org.gradle.usage" to "kotlin-api",
+ "org.jetbrains.kotlin.native.target" to "ios_arm64",
+ "org.jetbrains.kotlin.platform.type" to "native",
+ ),
+ files = listOf(
+ GradleMetadataComponent.StubVariantFile(
+ artifactId = "bar",
+ version = "1.0",
+ extension = "klib"
+ )
+ ),
+ dependencies = listOf()
+ )
+
+ private val kmpJvmApiVariant = Variant(
+ name = "jvmApiElements-published",
+ attributes = kmpJvmApiVariantAttributes,
+ files = listOf(
+ GradleMetadataComponent.StubVariantFile(
+ artifactId = "bar",
+ version = "1.0",
+ extension = "jar"
+ )
+ ),
+ dependencies = listOf()
+ )
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/generateMockRepository.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/generateMockRepository.kt
new file mode 100644
index 0000000..e64fa19
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/generateMockRepository.kt
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.unitTests.uklibs
+
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.encodeToJsonElement
+import kotlinx.serialization.json.jsonObject
+import org.junit.rules.TemporaryFolder
+import org.w3c.dom.Document
+import java.io.ByteArrayOutputStream
+import java.io.File
+import javax.xml.parsers.DocumentBuilderFactory
+import javax.xml.transform.OutputKeys
+import javax.xml.transform.TransformerFactory
+import javax.xml.transform.dom.DOMSource
+import javax.xml.transform.stream.StreamResult
+
+private val json = Json {
+ encodeDefaults = true
+ prettyPrint = true
+}
+
+class GradleComponent(
+ val module: GradleMetadataComponent,
+ val pom: MavenComponent,
+)
+
+@Serializable
+class GradleMetadataComponent(
+ val formatVersion: String = "1.1",
+ val component: Component,
+ val createdBy: Map<String, Map<String, String>> = mapOf(
+ "gradle" to mapOf(
+ "version" to "8.11.1"
+ )
+ ),
+ val variants: List<Variant>
+) {
+ @Serializable
+ class Component(
+ val group: String,
+ val module: String,
+ val version: String,
+ val attributes: Map<String, String> = mapOf(
+ "org.gradle.status" to "release"
+ ),
+ )
+
+ @Serializable
+ class Variant(
+ val name: String,
+ val attributes: Map<String, String>,
+ val dependencies: List<Component>,
+ val files: List<StubVariantFile> = emptyList(),
+ )
+
+ @Serializable
+ class StubVariantFile(
+ val url: String,
+ val name: String = url,
+ val size: Int = 0,
+ ) {
+ constructor(
+ artifactId: String,
+ version: String,
+ extension: String,
+ classifier: String? = null,
+ ) : this(listOfNotNull(artifactId, version, classifier).joinToString("-") + ".${extension}")
+ }
+
+ @Serializable
+ class Dependency(
+ val group: String,
+ val module: String,
+ val version: Version,
+ val attributes: Map<String, String>? = null,
+ )
+
+ @Serializable
+ class Version(
+ val requires: String,
+ )
+}
+
+class MavenComponent(
+ val groupId: String,
+ val artifactId: String,
+ val version: String,
+ val packaging: String,
+ val dependencies: List<Dependency>,
+ val gradleMetadataMarker: Boolean,
+) {
+ class Dependency(
+ val groupId: String?,
+ val artifactId: String?,
+ val version: String?,
+ val scope: String?,
+ )
+}
+
+fun generateMockRepository(
+ temporaryFolder: TemporaryFolder,
+ gradleComponents: List<GradleComponent> = emptyList(),
+ mavenComponents: List<MavenComponent> = emptyList(),
+): File {
+ val repositoryRoot = temporaryFolder.newFolder()
+ val repository = MockRepository(repositoryRoot)
+ gradleComponents.forEach {
+ repository.addGradleComponent(
+ it.module, it.pom
+ )
+ }
+ mavenComponents.forEach {
+ repository.addMavenComponent(it)
+ }
+ return repositoryRoot
+}
+
+private class MockRepository(
+ private val root: File
+) {
+ fun addGradleComponent(
+ gradleComponent: GradleMetadataComponent,
+ mavenComponent: MavenComponent,
+ ) {
+ val componentRoot = createComponentRoot(mavenComponent)
+ componentRoot.resolve("${mavenComponent.artifactId}-${mavenComponent.version}.pom").writeText(
+ generatePom(mavenComponent)
+ )
+ componentRoot.resolve("${mavenComponent.artifactId}-${mavenComponent.version}.module").writeText(
+ with(json.encodeToJsonElement(gradleComponent)) {
+ // Gradle requires that "formatVersion" field be the first in the module json
+ json.encodeToString(
+ jsonObject.entries
+ .sortedBy { (key, _) -> if (key == "formatVersion") 0 else 1 }
+ .map { it.key to it.value }
+ .toMap()
+ )
+ }
+ )
+ gradleComponent.variants.forEach { variant ->
+ variant.files.forEach { file ->
+ componentRoot.resolve(file.url).createNewFile()
+ }
+ }
+ }
+
+ fun addMavenComponent(mavenComponent: MavenComponent) {
+ val componentRoot = createComponentRoot(mavenComponent)
+ componentRoot.resolve("${mavenComponent.artifactId}-${mavenComponent.version}.pom").writeText(
+ generatePom(mavenComponent)
+ )
+ componentRoot.resolve("${mavenComponent.artifactId}-${mavenComponent.version}.jar").createNewFile()
+ }
+
+ private fun createComponentRoot(component: MavenComponent): File {
+ val path = component.groupId.split(".") + listOf(
+ component.artifactId,
+ component.version,
+ )
+ val componentRoot = root.resolve(path.joinToString("/"))
+ componentRoot.mkdirs()
+ return componentRoot
+ }
+
+ private fun generatePom(component: MavenComponent): String {
+ val doc: Document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
+
+ doc.appendChild(
+ doc.createElement("project").apply {
+ setAttribute("xmlns", "http://maven.apache.org/POM/4.0.0")
+ setAttribute("xsi:schemaLocation", "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd")
+ setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
+ if (component.gradleMetadataMarker) {
+ appendChild(
+ doc.createComment("do_not_remove: published-with-gradle-metadata")
+ )
+ }
+ appendChild(
+ doc.createElement("modelVersion").apply {
+ textContent = "4.0.0"
+ }
+ )
+ appendChild(
+ doc.createElement("groupId").apply {
+ textContent = component.groupId
+ }
+ )
+ appendChild(
+ doc.createElement("artifactId").apply {
+ textContent = component.artifactId
+ }
+ )
+ appendChild(
+ doc.createElement("version").apply {
+ textContent = component.version
+ }
+ )
+ appendChild(
+ doc.createElement("packaging").apply {
+ textContent = component.packaging
+ }
+ )
+ appendChild(
+ doc.createElement("dependencies").apply {
+ component.dependencies.forEach { dependency ->
+ appendChild(
+ doc.createElement("dependency").apply {
+ dependency.groupId?.let {
+ appendChild(
+ doc.createElement("groupId").apply {
+ textContent = it
+ }
+ )
+ }
+ dependency.artifactId?.let {
+ appendChild(
+ doc.createElement("artifactId").apply {
+ textContent = it
+ }
+ )
+ }
+ dependency.version?.let {
+ appendChild(
+ doc.createElement("version").apply {
+ textContent = it
+ }
+ )
+ }
+ dependency.scope?.let {
+ appendChild(
+ doc.createElement("scope").apply {
+ textContent = it
+ }
+ )
+ }
+ }
+ )
+ }
+ }
+ )
+ }
+ )
+
+ return ByteArrayOutputStream().apply {
+ TransformerFactory.newInstance().newTransformer().apply {
+ setOutputProperty(OutputKeys.INDENT, "yes")
+ setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")
+ }.transform(DOMSource(doc), StreamResult(this))
+ }.toString()
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/buildProject.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/buildProject.kt
index 0fc0b20..9876175 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/buildProject.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/buildProject.kt
@@ -13,7 +13,7 @@
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.testfixtures.ProjectBuilder
import org.gradle.testing.base.TestingExtension
-import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.UklibResolutionStrategy
+import org.jetbrains.kotlin.gradle.plugin.mpp.uklibs.consumption.KmpResolutionStrategy
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.*
@@ -143,8 +143,8 @@
propertiesExtension.set(PropertiesProvider.PropertyNames.KOTLIN_NATIVE_ENABLE_KLIBS_CROSSCOMPILATION, enabled.toString())
}
-internal fun Project.setUklibResolutionStrategy(strategy: UklibResolutionStrategy) {
- propertiesExtension.set(PropertiesProvider.PropertyNames.KOTLIN_KMP_UKLIB_RESOLUTION_STRATEGY, strategy.propertyName)
+internal fun Project.setUklibResolutionStrategy(strategy: KmpResolutionStrategy) {
+ propertiesExtension.set(PropertiesProvider.PropertyNames.KOTLIN_KMP_RESOLUTION_STRATEGY, strategy.propertyName)
}
fun Project.fakeUklibTransforms() {