From bd8aa8ae3da58e504e03322f8333bdc38bf7c8ac Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Mon, 8 Nov 2021 15:29:35 +0100 Subject: [PATCH] [Gradle][MPP] Include cinterop metadata directory in kotlin-project-structure-metadata.json - Also increase the KotlinProjectStructureMetadata's format version to 0.3.2 - Move new default location into /cinterop/{sourceSetName} ^KT-49596 Verification Pending --- .../kotlin/gradle/HierarchicalMppIT.kt | 1 + .../functionalTest.gradle.kts | 1 + .../kotlin/gradle/CompositeMetadataJarTest.kt | 42 ++- ...ojectStructureMetadataSerializationTest.kt | 64 +++++ ...tlin-project-structure-metadata.0_3_1.json | 243 ++++++++++++++++++ .../gradle/plugin/mpp/CompositeMetadataJar.kt | 10 +- .../mpp/KotlinProjectStructureMetadata.kt | 47 +++- ...CommonizerCompositeMetadataJarBundling.kt} | 9 +- .../jetbrains/kotlin/gradle/utils/zipUtils.kt | 13 +- 9 files changed, 405 insertions(+), 25 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/KotlinProjectStructureMetadataSerializationTest.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/coroutines-kotlin-project-structure-metadata.0_3_1.json rename libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/{CInteropCommonizerAllMetadataKlibBundling.kt => CInteropCommonizerCompositeMetadataJarBundling.kt} (73%) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt index 92e399b8872..cdb2a72c1ce 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt @@ -499,6 +499,7 @@ class HierarchicalMppIT : BaseGradleIT() { ModuleDependencyIdentifier(it.first, it.second) }.toSet() }, + sourceSetCInteropMetadataDirectory = mapOf(), hostSpecificSourceSets = emptySet(), sourceSetBinaryLayout = sourceSetModuleDependencies.mapValues { SourceSetMetadataLayout.KLIB }, isPublishedAsRoot = true diff --git a/libraries/tools/kotlin-gradle-plugin/functionalTest.gradle.kts b/libraries/tools/kotlin-gradle-plugin/functionalTest.gradle.kts index 55c126d1c5f..6808ed514d2 100644 --- a/libraries/tools/kotlin-gradle-plugin/functionalTest.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin/functionalTest.gradle.kts @@ -9,6 +9,7 @@ project.extensions.getByType().target.compilations { description = "Runs functional tests" testClassesDirs = output.classesDirs classpath = sourceSets["functionalTest"].runtimeClasspath + workingDir = projectDir } tasks.named("check") { dependsOn(functionalTest) diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/CompositeMetadataJarTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/CompositeMetadataJarTest.kt index 7f02ea29be8..a73ded64254 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/CompositeMetadataJarTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/CompositeMetadataJarTest.kt @@ -37,7 +37,34 @@ class CompositeMetadataJarTest { val metadataJar = CompositeMetadataJar( moduleIdentifier = "test-id", projectStructureMetadata = createProjectStructureMetadata( - sourceSetBinaryLayout = mapOf("testSourceSetName" to KLIB) + sourceSetBinaryLayout = mapOf("testSourceSetName" to KLIB), + sourceSetCInteropMetadataDirectory = mapOf("testSourceSetName" to "cinterop/testSourceSetName") + ), + primaryArtifactFile = primaryArtifactFile, + hostSpecificArtifactsBySourceSet = emptyMap() + ) + + val metadataOutputDirectory = temporaryFolder.newFolder() + val metadataFile = metadataJar.getSourceSetCompiledMetadata("testSourceSetName", metadataOutputDirectory, true) + + assertEquals( + File("test-id/test-id-testSourceSetName.klib"), + metadataFile.relativeTo(metadataOutputDirectory) + ) + } + + @Test + fun `empty jar - no cinterop metadata directory - get metadata - returns file`() { + val primaryArtifactContent = temporaryFolder.newFolder() + val primaryArtifactFile = temporaryFolder.newFile("metadata.jar") + zipTo(primaryArtifactFile, primaryArtifactContent) + assertTrue(primaryArtifactFile.isFile, "Expected primaryArtifactFile.isFile") + + val metadataJar = CompositeMetadataJar( + moduleIdentifier = "test-id", + projectStructureMetadata = createProjectStructureMetadata( + sourceSetBinaryLayout = mapOf("testSourceSetName" to KLIB), + sourceSetCInteropMetadataDirectory = emptyMap(), ), primaryArtifactFile = primaryArtifactFile, hostSpecificArtifactsBySourceSet = emptyMap() @@ -155,7 +182,7 @@ class CompositeMetadataJarTest { .withParentDirectoriesCreated() .writeText("stub2 content") - primaryArtifactContent.resolve("sourceSetB-cinterop/interopB0/stub3") + primaryArtifactContent.resolve("nested/sourceSetB/interops/interopB0/stub3") .withParentDirectoriesCreated() .writeText("stub3 content") @@ -165,7 +192,12 @@ class CompositeMetadataJarTest { val metadataJar = CompositeMetadataJar( moduleIdentifier = "test-id", - projectStructureMetadata = createProjectStructureMetadata(), + projectStructureMetadata = createProjectStructureMetadata( + sourceSetCInteropMetadataDirectory = mapOf( + "sourceSetA" to "sourceSetA-cinterop", + "sourceSetB" to "nested/sourceSetB/interops/" + ) + ), primaryArtifactFile = primaryArtifactFile, hostSpecificArtifactsBySourceSet = emptyMap() ) @@ -209,7 +241,7 @@ class CompositeMetadataJarTest { ?: fail("Failed to find 'interopB0.klib'") assertZipContentEquals( temporaryFolder, - primaryArtifactContent.resolve("sourceSetB-cinterop/interopB0"), interopB0MetadataFile, + primaryArtifactContent.resolve("nested/sourceSetB/interops/interopB0"), interopB0MetadataFile, "Expected correct content for extracted 'interopB0'" ) } @@ -219,6 +251,7 @@ class CompositeMetadataJarTest { private fun createProjectStructureMetadata( sourceSetNamesByVariantName: Map> = emptyMap(), sourceSetsDependsOnRelation: Map> = emptyMap(), + sourceSetCInteropMetadataDirectory: Map = emptyMap(), sourceSetBinaryLayout: Map = emptyMap(), sourceSetModuleDependencies: Map> = emptyMap(), hostSpecificSourceSets: Set = emptySet(), @@ -228,6 +261,7 @@ private fun createProjectStructureMetadata( sourceSetNamesByVariantName = sourceSetNamesByVariantName, sourceSetsDependsOnRelation = sourceSetsDependsOnRelation, sourceSetBinaryLayout = sourceSetBinaryLayout, + sourceSetCInteropMetadataDirectory = sourceSetCInteropMetadataDirectory, sourceSetModuleDependencies = sourceSetModuleDependencies, hostSpecificSourceSets = hostSpecificSourceSets, isPublishedAsRoot = isPublishedAsRoot diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/KotlinProjectStructureMetadataSerializationTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/KotlinProjectStructureMetadataSerializationTest.kt new file mode 100644 index 00000000000..a6e7a5d6fb7 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/KotlinProjectStructureMetadataSerializationTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("FunctionName") + +package org.jetbrains.kotlin.gradle + +import org.jetbrains.kotlin.gradle.plugin.mpp.* +import org.jetbrains.kotlin.gradle.plugin.mpp.SourceSetMetadataLayout.KLIB +import org.jetbrains.kotlin.gradle.plugin.mpp.SourceSetMetadataLayout.METADATA +import java.io.File +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +class KotlinProjectStructureMetadataSerializationTest { + + private val sampleMetadata = KotlinProjectStructureMetadata( + sourceSetNamesByVariantName = mapOf( + "sourceSetA" to setOf("value1", "value2"), "sourceSetB" to setOf("value3", "value4"), "sourceSetC" to setOf("value5") + ), + sourceSetsDependsOnRelation = mapOf( + "sourceSetA" to setOf("commonMain"), + "sourceSetB" to setOf("commonMain", "sourceSetA"), + "sourceSetC" to setOf("commonMain", "sourceSetB") + ), + sourceSetBinaryLayout = mapOf("sourceSetA" to METADATA, "sourceSetB" to KLIB, "sourceSetC" to KLIB), + sourceSetModuleDependencies = mapOf( + "sourceSetA" to setOf(ModuleDependencyIdentifier("aa", "bb")), + "sourceSetB" to setOf(ModuleDependencyIdentifier("cc", "dd"), ModuleDependencyIdentifier("ee", "ff")), + "sourceSetC" to emptySet() + ), + sourceSetCInteropMetadataDirectory = mapOf("sourceSetB" to "xx/cinterop/", "sourceSetC" to "cinterops/C"), + hostSpecificSourceSets = setOf("sourceSetC"), + isPublishedAsRoot = true + ) + + @Test + fun `serialize and deserialize - json`() { + val json = sampleMetadata.toJson() + val deserialized = parseKotlinSourceSetMetadataFromJson(json) + assertEquals(sampleMetadata, deserialized) + } + + @Test + fun `serialize and deserialize - xml`() { + val xml = sampleMetadata.toXmlDocument() + val deserialized = parseKotlinSourceSetMetadataFromXml(xml) + assertEquals(sampleMetadata, deserialized) + } + + @Test + fun `deserialize 0_3_1 format version built from coroutines`() { + val json = File("src/functionalTest/resources/coroutines-kotlin-project-structure-metadata.0_3_1.json").absoluteFile.readText() + val deserialized = assertNotNull(parseKotlinSourceSetMetadataFromJson(json)) + assertEquals(KotlinProjectStructureMetadata.FORMAT_VERSION_0_3_1, deserialized.formatVersion) + assertTrue(deserialized.isPublishedAsRoot) + assertEquals(setOf("commonMain", "concurrentMain"), deserialized.sourceSetsDependsOnRelation["nativeMain"]) + } + +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/coroutines-kotlin-project-structure-metadata.0_3_1.json b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/coroutines-kotlin-project-structure-metadata.0_3_1.json new file mode 100644 index 00000000000..878d7d82db7 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/coroutines-kotlin-project-structure-metadata.0_3_1.json @@ -0,0 +1,243 @@ +{ + "projectStructure": { + "formatVersion": "0.3.1", + "isPublishedAsRoot": "true", + "variants": [ + { + "name": "iosArm32ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "iosArm64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "iosSimulatorArm64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "iosX64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "jsLegacyApiElements", + "sourceSet": [ + "commonMain" + ] + }, + { + "name": "jsLegacyRuntimeElements", + "sourceSet": [ + "commonMain" + ] + }, + { + "name": "jsIrApiElements", + "sourceSet": [ + "commonMain" + ] + }, + { + "name": "jsIrRuntimeElements", + "sourceSet": [ + "commonMain" + ] + }, + { + "name": "jvmApiElements", + "sourceSet": [ + "commonMain", + "concurrentMain" + ] + }, + { + "name": "jvmRuntimeElements", + "sourceSet": [ + "commonMain", + "concurrentMain" + ] + }, + { + "name": "linuxX64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeOtherMain", + "concurrentMain" + ] + }, + { + "name": "macosArm64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "macosX64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "mingwX64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeOtherMain", + "concurrentMain" + ] + }, + { + "name": "tvosArm64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "tvosSimulatorArm64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "tvosX64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "watchosArm32ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "watchosArm64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "watchosSimulatorArm64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "watchosX64ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + }, + { + "name": "watchosX86ApiElements", + "sourceSet": [ + "commonMain", + "nativeMain", + "nativeDarwinMain", + "concurrentMain" + ] + } + ], + "sourceSets": [ + { + "name": "commonMain", + "dependsOn": [], + "moduleDependency": [ + "org.jetbrains.kotlin:kotlin-stdlib-common" + ], + "binaryLayout": "klib" + }, + { + "name": "concurrentMain", + "dependsOn": [ + "commonMain" + ], + "moduleDependency": [], + "binaryLayout": "klib" + }, + { + "name": "nativeDarwinMain", + "dependsOn": [ + "nativeMain" + ], + "moduleDependency": [ + "org.jetbrains.kotlin:kotlin-stdlib-common", + "org.jetbrains.kotlinx:atomicfu" + ], + "binaryLayout": "klib", + "hostSpecific": "true" + }, + { + "name": "nativeMain", + "dependsOn": [ + "commonMain", + "concurrentMain" + ], + "moduleDependency": [ + "org.jetbrains.kotlin:kotlin-stdlib-common", + "org.jetbrains.kotlinx:atomicfu" + ], + "binaryLayout": "klib" + }, + { + "name": "nativeOtherMain", + "dependsOn": [ + "nativeMain" + ], + "moduleDependency": [ + "org.jetbrains.kotlin:kotlin-stdlib-common", + "org.jetbrains.kotlinx:atomicfu" + ], + "binaryLayout": "klib" + } + ] + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompositeMetadataJar.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompositeMetadataJar.kt index 612c9c897a5..626dcb55689 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompositeMetadataJar.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompositeMetadataJar.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.jetbrains.kotlin.gradle.utils.copyZipFilePartially +import org.jetbrains.kotlin.gradle.utils.ensureValidZipDirectoryPath import org.jetbrains.kotlin.gradle.utils.listDescendants import java.io.File import java.util.zip.ZipFile @@ -72,16 +73,17 @@ private class CompositeMetadataJarImpl( val moduleOutputDirectory = outputDirectory.resolve(moduleIdentifier).also(File::mkdirs) ZipFile(getArtifactFile(sourceSetName)).use { artifactZipFile -> - val cinteropRootPath = "$sourceSetName-cinterop/" - val cinteropEntries = artifactZipFile.listDescendants(cinteropRootPath) + val cinteropMetadataDirectory = projectStructureMetadata.sourceSetCInteropMetadataDirectory[sourceSetName] ?: return emptySet() + val cinteropMetadataDirectoryPath = ensureValidZipDirectoryPath(cinteropMetadataDirectory) + val cinteropEntries = artifactZipFile.listDescendants(cinteropMetadataDirectoryPath) val cinteropNames = cinteropEntries.map { entry -> - entry.name.removePrefix(cinteropRootPath).split("/", limit = 2).first() + entry.name.removePrefix(cinteropMetadataDirectoryPath).split("/", limit = 2).first() }.toSet() val cinteropsByOutputFile = cinteropNames.associateBy { cinteropName -> moduleOutputDirectory.resolve("$cinteropName.klib") } if (materializeFiles) { cinteropsByOutputFile.forEach { (cinteropOutputFile, cinteropName) -> - copyZipFilePartially(artifactFile, cinteropOutputFile, "$cinteropRootPath$cinteropName/") + copyZipFilePartially(artifactFile, cinteropOutputFile, "$cinteropMetadataDirectoryPath$cinteropName/") } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt index 6a8c61257fa..5b9e25ac5c7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurati import org.jetbrains.kotlin.gradle.targets.metadata.dependsOnClosureWithInterCompilationDependencies import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations import org.jetbrains.kotlin.gradle.targets.metadata.isSharedNativeSourceSet +import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerCompositeMetadataJarBundling.cinteropMetadataDirectoryPath import org.w3c.dom.Document import org.w3c.dom.Element import org.w3c.dom.Node @@ -105,6 +106,9 @@ data class KotlinProjectStructureMetadata( @Internal val sourceSetModuleDependencies: Map>, + @Input + val sourceSetCInteropMetadataDirectory: Map, + @Input val hostSpecificSourceSets: Set, @@ -112,7 +116,7 @@ data class KotlinProjectStructureMetadata( val isPublishedAsRoot: Boolean, @Input - val formatVersion: String = FORMAT_VERSION_0_3_1 + val formatVersion: String = FORMAT_VERSION_0_3_2 ) : Serializable { @Suppress("UNUSED") // Gradle input @get:Input @@ -130,6 +134,9 @@ data class KotlinProjectStructureMetadata( // + 'isPublishedInRootModule' top-level flag internal const val FORMAT_VERSION_0_3_1 = "0.3.1" + + // + 'sourceSetCInteropMetadataDirectory' map + internal const val FORMAT_VERSION_0_3_2 = "0.3.2" } } @@ -173,6 +180,9 @@ internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjec } sourceSet.name to sourceSetExportedDependencies.map { ModuleIds.fromDependency(it) }.toSet() }, + sourceSetCInteropMetadataDirectory = sourceSetsWithMetadataCompilations.keys + .filter { isSharedNativeSourceSet(project, it) } + .associate { sourceSet -> sourceSet.name to cinteropMetadataDirectoryPath(sourceSet.name) }, hostSpecificSourceSets = getHostSpecificSourceSets(project) .filter { it in sourceSetsWithMetadataCompilations }.map { it.name } .toSet(), @@ -206,11 +216,12 @@ internal fun buildProjectStructureMetadata(module: KotlinGradleModule): KotlinPr } return KotlinProjectStructureMetadata( - expandVariantKeys(kotlinFragmentsPerKotlinVariant), - fragmentRefinesRelation, - module.fragments.associate { it.name to SourceSetMetadataLayout.KLIB }, - fragmentDependencies, - getHostSpecificFragments(module).mapTo(mutableSetOf()) { it.name }, + sourceSetNamesByVariantName = expandVariantKeys(kotlinFragmentsPerKotlinVariant), + sourceSetsDependsOnRelation = fragmentRefinesRelation, + sourceSetBinaryLayout = module.fragments.associate { it.name to SourceSetMetadataLayout.KLIB }, + sourceSetModuleDependencies = fragmentDependencies, + sourceSetCInteropMetadataDirectory = emptyMap(), // Not supported yet + hostSpecificSourceSets = getHostSpecificFragments(module).mapTo(mutableSetOf()) { it.name }, isPublishedAsRoot = true ) } @@ -246,6 +257,9 @@ internal fun KotlinProjectStructureMetadata.serialize( multiValue(MODULE_DEPENDENCY_NODE_NAME, sourceSetModuleDependencies[sourceSet].orEmpty().map { moduleDependency -> moduleDependency.groupId + ":" + moduleDependency.moduleId }) + sourceSetCInteropMetadataDirectory[sourceSet]?.let { cinteropMetadataDirectory -> + value(SOURCE_SET_CINTEROP_METADATA_NODE_NAME, cinteropMetadataDirectory) + } sourceSetBinaryLayout[sourceSet]?.let { binaryLayout -> value(BINARY_LAYOUT_NODE_NAME, binaryLayout.name) } @@ -335,6 +349,7 @@ internal fun parseKotlinSourceSetMetadata( val sourceSetDependsOnRelation = mutableMapOf>() val sourceSetModuleDependencies = mutableMapOf>() val sourceSetBinaryLayout = mutableMapOf() + val sourceSetCInteropMetadataDirectory = mutableMapOf() val hostSpecificSourceSets = mutableSetOf() val sourceSetsNode = projectStructureNode.multiObjects(SOURCE_SETS_NODE_NAME) @@ -348,6 +363,10 @@ internal fun parseKotlinSourceSetMetadata( ModuleDependencyIdentifier(groupId, moduleId) } + sourceSetNode.valueNamed(SOURCE_SET_CINTEROP_METADATA_NODE_NAME)?.let { cinteropMetadataDirectory -> + sourceSetCInteropMetadataDirectory[sourceSetName] = cinteropMetadataDirectory + } + sourceSetNode.valueNamed(HOST_SPECIFIC_NODE_NAME) ?.let { if (it.toBoolean()) hostSpecificSourceSets.add(sourceSetName) } @@ -360,13 +379,14 @@ internal fun parseKotlinSourceSetMetadata( } return KotlinProjectStructureMetadata( - sourceSetsByVariant, - sourceSetDependsOnRelation, - sourceSetBinaryLayout, - sourceSetModuleDependencies, - hostSpecificSourceSets, - isPublishedAsRoot, - formatVersion + sourceSetNamesByVariantName = sourceSetsByVariant, + sourceSetsDependsOnRelation = sourceSetDependsOnRelation, + sourceSetBinaryLayout = sourceSetBinaryLayout, + sourceSetModuleDependencies = sourceSetModuleDependencies, + sourceSetCInteropMetadataDirectory = sourceSetCInteropMetadataDirectory, + hostSpecificSourceSets = hostSpecificSourceSets, + isPublishedAsRoot = isPublishedAsRoot, + formatVersion = formatVersion ) } @@ -403,6 +423,7 @@ private const val VARIANT_NODE_NAME = "variant" private const val NAME_NODE_NAME = "name" private const val SOURCE_SETS_NODE_NAME = "sourceSets" private const val SOURCE_SET_NODE_NAME = "sourceSet" +private const val SOURCE_SET_CINTEROP_METADATA_NODE_NAME = "sourceSetCInteropMetadataDirectory" private const val DEPENDS_ON_NODE_NAME = "dependsOn" private const val MODULE_DEPENDENCY_NODE_NAME = "moduleDependency" private const val BINARY_LAYOUT_NODE_NAME = "binaryLayout" diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerAllMetadataKlibBundling.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerCompositeMetadataJarBundling.kt similarity index 73% rename from libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerAllMetadataKlibBundling.kt rename to libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerCompositeMetadataJarBundling.kt index 7d56724b5b7..2444c69b7d1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerAllMetadataKlibBundling.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerCompositeMetadataJarBundling.kt @@ -9,6 +9,7 @@ import org.gradle.api.Project import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.bundling.Zip import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation +import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerCompositeMetadataJarBundling.cinteropMetadataDirectoryPath internal fun Project.includeCommonizedCInteropMetadata( metadataKlib: TaskProvider, compilation: KotlinSharedNativeCompilation @@ -22,6 +23,12 @@ internal fun Project.includeCommonizedCInteropMetadata(metadataKlib: Zip, compil val outputDirectory = commonizerTask.commonizedOutputDirectory(commonizerDependencyToken) ?: return metadataKlib.from(outputDirectory) { spec -> - spec.into(compilation.defaultSourceSet.name + "-cinterop") + spec.into(cinteropMetadataDirectoryPath(compilation.defaultSourceSetName)) + } +} + +internal object CInteropCommonizerCompositeMetadataJarBundling { + fun cinteropMetadataDirectoryPath(sourceSetName: String): String { + return "cinterop/$sourceSetName/" } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/zipUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/zipUtils.kt index d0d5e0bd35a..5c2ec6017bc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/zipUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/zipUtils.kt @@ -11,7 +11,7 @@ import java.util.zip.ZipFile import java.util.zip.ZipOutputStream internal fun copyZipFilePartially(sourceZipFile: File, destinationZipFile: File, path: String) { - requireValidZipPath(path) + requireValidZipDirectoryPath(path) ZipFile(sourceZipFile).use { zip -> val entries = zip.listDescendants(path).toList() @@ -35,12 +35,19 @@ internal fun copyZipFilePartially(sourceZipFile: File, destinationZipFile: File, } internal fun ZipFile.listDescendants(path: String): Sequence { - requireValidZipPath(path) + requireValidZipDirectoryPath(path) return entries().asSequence().filter { entry -> entry.name != path && entry.name.startsWith(path) } } -private fun requireValidZipPath(path: String) = require(path.isEmpty() || path.endsWith("/")) { +internal fun ensureValidZipDirectoryPath(path: String): String { + if (isValidZipDirectoryPath(path)) return path + return "$path/".also(::requireValidZipDirectoryPath) +} + +private fun requireValidZipDirectoryPath(path: String) = require(isValidZipDirectoryPath(path)) { "Expected path to end with '/', found '$path'" } + +private fun isValidZipDirectoryPath(path: String) = path.isEmpty() || path.endsWith("/")