[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
This commit is contained in:
sebastian.sellmair
2021-11-08 15:29:35 +01:00
committed by Space
parent 7b017fad90
commit bd8aa8ae3d
9 changed files with 405 additions and 25 deletions
@@ -499,6 +499,7 @@ class HierarchicalMppIT : BaseGradleIT() {
ModuleDependencyIdentifier(it.first, it.second) ModuleDependencyIdentifier(it.first, it.second)
}.toSet() }.toSet()
}, },
sourceSetCInteropMetadataDirectory = mapOf(),
hostSpecificSourceSets = emptySet(), hostSpecificSourceSets = emptySet(),
sourceSetBinaryLayout = sourceSetModuleDependencies.mapValues { SourceSetMetadataLayout.KLIB }, sourceSetBinaryLayout = sourceSetModuleDependencies.mapValues { SourceSetMetadataLayout.KLIB },
isPublishedAsRoot = true isPublishedAsRoot = true
@@ -9,6 +9,7 @@ project.extensions.getByType<KotlinJvmProjectExtension>().target.compilations {
description = "Runs functional tests" description = "Runs functional tests"
testClassesDirs = output.classesDirs testClassesDirs = output.classesDirs
classpath = sourceSets["functionalTest"].runtimeClasspath classpath = sourceSets["functionalTest"].runtimeClasspath
workingDir = projectDir
} }
tasks.named("check") { tasks.named("check") {
dependsOn(functionalTest) dependsOn(functionalTest)
@@ -37,7 +37,34 @@ class CompositeMetadataJarTest {
val metadataJar = CompositeMetadataJar( val metadataJar = CompositeMetadataJar(
moduleIdentifier = "test-id", moduleIdentifier = "test-id",
projectStructureMetadata = createProjectStructureMetadata( 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, primaryArtifactFile = primaryArtifactFile,
hostSpecificArtifactsBySourceSet = emptyMap() hostSpecificArtifactsBySourceSet = emptyMap()
@@ -155,7 +182,7 @@ class CompositeMetadataJarTest {
.withParentDirectoriesCreated() .withParentDirectoriesCreated()
.writeText("stub2 content") .writeText("stub2 content")
primaryArtifactContent.resolve("sourceSetB-cinterop/interopB0/stub3") primaryArtifactContent.resolve("nested/sourceSetB/interops/interopB0/stub3")
.withParentDirectoriesCreated() .withParentDirectoriesCreated()
.writeText("stub3 content") .writeText("stub3 content")
@@ -165,7 +192,12 @@ class CompositeMetadataJarTest {
val metadataJar = CompositeMetadataJar( val metadataJar = CompositeMetadataJar(
moduleIdentifier = "test-id", moduleIdentifier = "test-id",
projectStructureMetadata = createProjectStructureMetadata(), projectStructureMetadata = createProjectStructureMetadata(
sourceSetCInteropMetadataDirectory = mapOf(
"sourceSetA" to "sourceSetA-cinterop",
"sourceSetB" to "nested/sourceSetB/interops/"
)
),
primaryArtifactFile = primaryArtifactFile, primaryArtifactFile = primaryArtifactFile,
hostSpecificArtifactsBySourceSet = emptyMap() hostSpecificArtifactsBySourceSet = emptyMap()
) )
@@ -209,7 +241,7 @@ class CompositeMetadataJarTest {
?: fail("Failed to find 'interopB0.klib'") ?: fail("Failed to find 'interopB0.klib'")
assertZipContentEquals( assertZipContentEquals(
temporaryFolder, temporaryFolder,
primaryArtifactContent.resolve("sourceSetB-cinterop/interopB0"), interopB0MetadataFile, primaryArtifactContent.resolve("nested/sourceSetB/interops/interopB0"), interopB0MetadataFile,
"Expected correct content for extracted 'interopB0'" "Expected correct content for extracted 'interopB0'"
) )
} }
@@ -219,6 +251,7 @@ class CompositeMetadataJarTest {
private fun createProjectStructureMetadata( private fun createProjectStructureMetadata(
sourceSetNamesByVariantName: Map<String, Set<String>> = emptyMap(), sourceSetNamesByVariantName: Map<String, Set<String>> = emptyMap(),
sourceSetsDependsOnRelation: Map<String, Set<String>> = emptyMap(), sourceSetsDependsOnRelation: Map<String, Set<String>> = emptyMap(),
sourceSetCInteropMetadataDirectory: Map<String, String> = emptyMap(),
sourceSetBinaryLayout: Map<String, SourceSetMetadataLayout> = emptyMap(), sourceSetBinaryLayout: Map<String, SourceSetMetadataLayout> = emptyMap(),
sourceSetModuleDependencies: Map<String, Set<ModuleDependencyIdentifier>> = emptyMap(), sourceSetModuleDependencies: Map<String, Set<ModuleDependencyIdentifier>> = emptyMap(),
hostSpecificSourceSets: Set<String> = emptySet(), hostSpecificSourceSets: Set<String> = emptySet(),
@@ -228,6 +261,7 @@ private fun createProjectStructureMetadata(
sourceSetNamesByVariantName = sourceSetNamesByVariantName, sourceSetNamesByVariantName = sourceSetNamesByVariantName,
sourceSetsDependsOnRelation = sourceSetsDependsOnRelation, sourceSetsDependsOnRelation = sourceSetsDependsOnRelation,
sourceSetBinaryLayout = sourceSetBinaryLayout, sourceSetBinaryLayout = sourceSetBinaryLayout,
sourceSetCInteropMetadataDirectory = sourceSetCInteropMetadataDirectory,
sourceSetModuleDependencies = sourceSetModuleDependencies, sourceSetModuleDependencies = sourceSetModuleDependencies,
hostSpecificSourceSets = hostSpecificSourceSets, hostSpecificSourceSets = hostSpecificSourceSets,
isPublishedAsRoot = isPublishedAsRoot isPublishedAsRoot = isPublishedAsRoot
@@ -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"])
}
}
@@ -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"
}
]
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.mpp package org.jetbrains.kotlin.gradle.plugin.mpp
import org.jetbrains.kotlin.gradle.utils.copyZipFilePartially import org.jetbrains.kotlin.gradle.utils.copyZipFilePartially
import org.jetbrains.kotlin.gradle.utils.ensureValidZipDirectoryPath
import org.jetbrains.kotlin.gradle.utils.listDescendants import org.jetbrains.kotlin.gradle.utils.listDescendants
import java.io.File import java.io.File
import java.util.zip.ZipFile import java.util.zip.ZipFile
@@ -72,16 +73,17 @@ private class CompositeMetadataJarImpl(
val moduleOutputDirectory = outputDirectory.resolve(moduleIdentifier).also(File::mkdirs) val moduleOutputDirectory = outputDirectory.resolve(moduleIdentifier).also(File::mkdirs)
ZipFile(getArtifactFile(sourceSetName)).use { artifactZipFile -> ZipFile(getArtifactFile(sourceSetName)).use { artifactZipFile ->
val cinteropRootPath = "$sourceSetName-cinterop/" val cinteropMetadataDirectory = projectStructureMetadata.sourceSetCInteropMetadataDirectory[sourceSetName] ?: return emptySet()
val cinteropEntries = artifactZipFile.listDescendants(cinteropRootPath) val cinteropMetadataDirectoryPath = ensureValidZipDirectoryPath(cinteropMetadataDirectory)
val cinteropEntries = artifactZipFile.listDescendants(cinteropMetadataDirectoryPath)
val cinteropNames = cinteropEntries.map { entry -> val cinteropNames = cinteropEntries.map { entry ->
entry.name.removePrefix(cinteropRootPath).split("/", limit = 2).first() entry.name.removePrefix(cinteropMetadataDirectoryPath).split("/", limit = 2).first()
}.toSet() }.toSet()
val cinteropsByOutputFile = cinteropNames.associateBy { cinteropName -> moduleOutputDirectory.resolve("$cinteropName.klib") } val cinteropsByOutputFile = cinteropNames.associateBy { cinteropName -> moduleOutputDirectory.resolve("$cinteropName.klib") }
if (materializeFiles) { if (materializeFiles) {
cinteropsByOutputFile.forEach { (cinteropOutputFile, cinteropName) -> cinteropsByOutputFile.forEach { (cinteropOutputFile, cinteropName) ->
copyZipFilePartially(artifactFile, cinteropOutputFile, "$cinteropRootPath$cinteropName/") copyZipFilePartially(artifactFile, cinteropOutputFile, "$cinteropMetadataDirectoryPath$cinteropName/")
} }
} }
@@ -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.dependsOnClosureWithInterCompilationDependencies
import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations
import org.jetbrains.kotlin.gradle.targets.metadata.isSharedNativeSourceSet 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.Document
import org.w3c.dom.Element import org.w3c.dom.Element
import org.w3c.dom.Node import org.w3c.dom.Node
@@ -105,6 +106,9 @@ data class KotlinProjectStructureMetadata(
@Internal @Internal
val sourceSetModuleDependencies: Map<String, Set<ModuleDependencyIdentifier>>, val sourceSetModuleDependencies: Map<String, Set<ModuleDependencyIdentifier>>,
@Input
val sourceSetCInteropMetadataDirectory: Map<String, String>,
@Input @Input
val hostSpecificSourceSets: Set<String>, val hostSpecificSourceSets: Set<String>,
@@ -112,7 +116,7 @@ data class KotlinProjectStructureMetadata(
val isPublishedAsRoot: Boolean, val isPublishedAsRoot: Boolean,
@Input @Input
val formatVersion: String = FORMAT_VERSION_0_3_1 val formatVersion: String = FORMAT_VERSION_0_3_2
) : Serializable { ) : Serializable {
@Suppress("UNUSED") // Gradle input @Suppress("UNUSED") // Gradle input
@get:Input @get:Input
@@ -130,6 +134,9 @@ data class KotlinProjectStructureMetadata(
// + 'isPublishedInRootModule' top-level flag // + 'isPublishedInRootModule' top-level flag
internal const val FORMAT_VERSION_0_3_1 = "0.3.1" 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() 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) hostSpecificSourceSets = getHostSpecificSourceSets(project)
.filter { it in sourceSetsWithMetadataCompilations }.map { it.name } .filter { it in sourceSetsWithMetadataCompilations }.map { it.name }
.toSet(), .toSet(),
@@ -206,11 +216,12 @@ internal fun buildProjectStructureMetadata(module: KotlinGradleModule): KotlinPr
} }
return KotlinProjectStructureMetadata( return KotlinProjectStructureMetadata(
expandVariantKeys(kotlinFragmentsPerKotlinVariant), sourceSetNamesByVariantName = expandVariantKeys(kotlinFragmentsPerKotlinVariant),
fragmentRefinesRelation, sourceSetsDependsOnRelation = fragmentRefinesRelation,
module.fragments.associate { it.name to SourceSetMetadataLayout.KLIB }, sourceSetBinaryLayout = module.fragments.associate { it.name to SourceSetMetadataLayout.KLIB },
fragmentDependencies, sourceSetModuleDependencies = fragmentDependencies,
getHostSpecificFragments(module).mapTo(mutableSetOf()) { it.name }, sourceSetCInteropMetadataDirectory = emptyMap(), // Not supported yet
hostSpecificSourceSets = getHostSpecificFragments(module).mapTo(mutableSetOf()) { it.name },
isPublishedAsRoot = true isPublishedAsRoot = true
) )
} }
@@ -246,6 +257,9 @@ internal fun <Serializer> KotlinProjectStructureMetadata.serialize(
multiValue(MODULE_DEPENDENCY_NODE_NAME, sourceSetModuleDependencies[sourceSet].orEmpty().map { moduleDependency -> multiValue(MODULE_DEPENDENCY_NODE_NAME, sourceSetModuleDependencies[sourceSet].orEmpty().map { moduleDependency ->
moduleDependency.groupId + ":" + moduleDependency.moduleId moduleDependency.groupId + ":" + moduleDependency.moduleId
}) })
sourceSetCInteropMetadataDirectory[sourceSet]?.let { cinteropMetadataDirectory ->
value(SOURCE_SET_CINTEROP_METADATA_NODE_NAME, cinteropMetadataDirectory)
}
sourceSetBinaryLayout[sourceSet]?.let { binaryLayout -> sourceSetBinaryLayout[sourceSet]?.let { binaryLayout ->
value(BINARY_LAYOUT_NODE_NAME, binaryLayout.name) value(BINARY_LAYOUT_NODE_NAME, binaryLayout.name)
} }
@@ -335,6 +349,7 @@ internal fun <ParsingContext> parseKotlinSourceSetMetadata(
val sourceSetDependsOnRelation = mutableMapOf<String, Set<String>>() val sourceSetDependsOnRelation = mutableMapOf<String, Set<String>>()
val sourceSetModuleDependencies = mutableMapOf<String, Set<ModuleDependencyIdentifier>>() val sourceSetModuleDependencies = mutableMapOf<String, Set<ModuleDependencyIdentifier>>()
val sourceSetBinaryLayout = mutableMapOf<String, SourceSetMetadataLayout>() val sourceSetBinaryLayout = mutableMapOf<String, SourceSetMetadataLayout>()
val sourceSetCInteropMetadataDirectory = mutableMapOf<String, String>()
val hostSpecificSourceSets = mutableSetOf<String>() val hostSpecificSourceSets = mutableSetOf<String>()
val sourceSetsNode = projectStructureNode.multiObjects(SOURCE_SETS_NODE_NAME) val sourceSetsNode = projectStructureNode.multiObjects(SOURCE_SETS_NODE_NAME)
@@ -348,6 +363,10 @@ internal fun <ParsingContext> parseKotlinSourceSetMetadata(
ModuleDependencyIdentifier(groupId, moduleId) ModuleDependencyIdentifier(groupId, moduleId)
} }
sourceSetNode.valueNamed(SOURCE_SET_CINTEROP_METADATA_NODE_NAME)?.let { cinteropMetadataDirectory ->
sourceSetCInteropMetadataDirectory[sourceSetName] = cinteropMetadataDirectory
}
sourceSetNode.valueNamed(HOST_SPECIFIC_NODE_NAME) sourceSetNode.valueNamed(HOST_SPECIFIC_NODE_NAME)
?.let { if (it.toBoolean()) hostSpecificSourceSets.add(sourceSetName) } ?.let { if (it.toBoolean()) hostSpecificSourceSets.add(sourceSetName) }
@@ -360,13 +379,14 @@ internal fun <ParsingContext> parseKotlinSourceSetMetadata(
} }
return KotlinProjectStructureMetadata( return KotlinProjectStructureMetadata(
sourceSetsByVariant, sourceSetNamesByVariantName = sourceSetsByVariant,
sourceSetDependsOnRelation, sourceSetsDependsOnRelation = sourceSetDependsOnRelation,
sourceSetBinaryLayout, sourceSetBinaryLayout = sourceSetBinaryLayout,
sourceSetModuleDependencies, sourceSetModuleDependencies = sourceSetModuleDependencies,
hostSpecificSourceSets, sourceSetCInteropMetadataDirectory = sourceSetCInteropMetadataDirectory,
isPublishedAsRoot, hostSpecificSourceSets = hostSpecificSourceSets,
formatVersion 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 NAME_NODE_NAME = "name"
private const val SOURCE_SETS_NODE_NAME = "sourceSets" private const val SOURCE_SETS_NODE_NAME = "sourceSets"
private const val SOURCE_SET_NODE_NAME = "sourceSet" 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 DEPENDS_ON_NODE_NAME = "dependsOn"
private const val MODULE_DEPENDENCY_NODE_NAME = "moduleDependency" private const val MODULE_DEPENDENCY_NODE_NAME = "moduleDependency"
private const val BINARY_LAYOUT_NODE_NAME = "binaryLayout" private const val BINARY_LAYOUT_NODE_NAME = "binaryLayout"
@@ -9,6 +9,7 @@ import org.gradle.api.Project
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Zip import org.gradle.api.tasks.bundling.Zip
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerCompositeMetadataJarBundling.cinteropMetadataDirectoryPath
internal fun Project.includeCommonizedCInteropMetadata( internal fun Project.includeCommonizedCInteropMetadata(
metadataKlib: TaskProvider<out Zip>, compilation: KotlinSharedNativeCompilation metadataKlib: TaskProvider<out Zip>, compilation: KotlinSharedNativeCompilation
@@ -22,6 +23,12 @@ internal fun Project.includeCommonizedCInteropMetadata(metadataKlib: Zip, compil
val outputDirectory = commonizerTask.commonizedOutputDirectory(commonizerDependencyToken) ?: return val outputDirectory = commonizerTask.commonizedOutputDirectory(commonizerDependencyToken) ?: return
metadataKlib.from(outputDirectory) { spec -> 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/"
} }
} }
@@ -11,7 +11,7 @@ import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
internal fun copyZipFilePartially(sourceZipFile: File, destinationZipFile: File, path: String) { internal fun copyZipFilePartially(sourceZipFile: File, destinationZipFile: File, path: String) {
requireValidZipPath(path) requireValidZipDirectoryPath(path)
ZipFile(sourceZipFile).use { zip -> ZipFile(sourceZipFile).use { zip ->
val entries = zip.listDescendants(path).toList() val entries = zip.listDescendants(path).toList()
@@ -35,12 +35,19 @@ internal fun copyZipFilePartially(sourceZipFile: File, destinationZipFile: File,
} }
internal fun ZipFile.listDescendants(path: String): Sequence<ZipEntry> { internal fun ZipFile.listDescendants(path: String): Sequence<ZipEntry> {
requireValidZipPath(path) requireValidZipDirectoryPath(path)
return entries().asSequence().filter { entry -> return entries().asSequence().filter { entry ->
entry.name != path && entry.name.startsWith(path) 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'" "Expected path to end with '/', found '$path'"
} }
private fun isValidZipDirectoryPath(path: String) = path.isEmpty() || path.endsWith("/")