[Gradle][MPP] Implement CompositeMetadataArtifact
^KT-48135 WIP
This commit is contained in:
committed by
Space
parent
244094501b
commit
7a1f4304d0
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
|
||||
internal interface CompositeMetadataArtifact {
|
||||
|
||||
interface Library {
|
||||
val artifactHandle: ArtifactHandle
|
||||
val sourceSet: SourceSet
|
||||
val archiveExtension: String
|
||||
|
||||
/**
|
||||
* The proposed file-output path.
|
||||
* This can actually include several path parts if the [Library] requires additional scoping (e.g. [CInteropMetadataLibrary]s
|
||||
* need to be put into another folder)
|
||||
*/
|
||||
val relativeFile: File
|
||||
|
||||
/**
|
||||
* Copies the content of this [Library] directly into the given [file].
|
||||
* The [file] will be overwritten when it already exists.
|
||||
* Parent directories will be created if necessary.
|
||||
*/
|
||||
fun copyTo(file: File): Boolean
|
||||
|
||||
/**
|
||||
* Copies the content of this [Library] into the [directory] appending the [relativeFile] to it.
|
||||
* @see copyTo
|
||||
*/
|
||||
fun copyIntoDirectory(directory: File) = copyTo(directory.resolve(relativeFile))
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a Kotlin Metadata library produced by compiling the contained [sourceSet]
|
||||
*/
|
||||
interface MetadataLibrary : Library
|
||||
|
||||
/**
|
||||
* Represents a CInterop Metadata library, produced by the commonizer and attached to the [sourceSet]
|
||||
*/
|
||||
interface CInteropMetadataLibrary : Library {
|
||||
val cinteropLibraryName: String
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a SourceSet packaged into the [CompositeMetadataArtifact]
|
||||
*/
|
||||
interface SourceSet {
|
||||
val artifactHandle: ArtifactHandle
|
||||
val sourceSetName: String
|
||||
val metadataLibrary: MetadataLibrary?
|
||||
val cinteropMetadataLibraries: List<CInteropMetadataLibrary>
|
||||
}
|
||||
|
||||
interface ArtifactHandle : Closeable {
|
||||
val moduleDependencyIdentifier: ModuleDependencyIdentifier
|
||||
val moduleDependencyVersion: String
|
||||
val sourceSets: List<SourceSet>
|
||||
fun getSourceSet(name: String): SourceSet
|
||||
fun findSourceSet(name: String): SourceSet?
|
||||
}
|
||||
|
||||
val moduleDependencyIdentifier: ModuleDependencyIdentifier
|
||||
val moduleDependencyVersion: String
|
||||
|
||||
fun open(): ArtifactHandle
|
||||
|
||||
fun <T> read(action: (artifactHandle: ArtifactHandle) -> T): T {
|
||||
return open().use(action)
|
||||
}
|
||||
}
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||
|
||||
import org.jetbrains.kotlin.gradle.utils.copyPartially
|
||||
import org.jetbrains.kotlin.gradle.utils.ensureValidZipDirectoryPath
|
||||
import org.jetbrains.kotlin.gradle.utils.listDescendants
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
internal class CompositeMetadataArtifactImpl(
|
||||
override val moduleDependencyIdentifier: ModuleDependencyIdentifier,
|
||||
override val moduleDependencyVersion: String,
|
||||
private val kotlinProjectStructureMetadata: KotlinProjectStructureMetadata,
|
||||
private val primaryArtifactFile: File,
|
||||
private val hostSpecificArtifactFilesBySourceSetName: Map<String, File>
|
||||
) : CompositeMetadataArtifact {
|
||||
|
||||
override fun open(): CompositeMetadataArtifact.ArtifactHandle {
|
||||
return HandlerImpl()
|
||||
}
|
||||
|
||||
inner class HandlerImpl : CompositeMetadataArtifact.ArtifactHandle {
|
||||
|
||||
override val moduleDependencyIdentifier: ModuleDependencyIdentifier
|
||||
get() = this@CompositeMetadataArtifactImpl.moduleDependencyIdentifier
|
||||
|
||||
override val moduleDependencyVersion: String
|
||||
get() = this@CompositeMetadataArtifactImpl.moduleDependencyVersion
|
||||
|
||||
/* Creating SourceSet instances eagerly, as they will only lazily access files */
|
||||
private val sourceSetsImpl = kotlinProjectStructureMetadata.sourceSetNames.associateWith { sourceSetName ->
|
||||
SourceSetImpl(this, sourceSetName, ArtifactFile(hostSpecificArtifactFilesBySourceSetName[sourceSetName] ?: primaryArtifactFile))
|
||||
}
|
||||
|
||||
override val sourceSets: List<CompositeMetadataArtifact.SourceSet> =
|
||||
sourceSetsImpl.values.toList()
|
||||
|
||||
override fun getSourceSet(name: String): CompositeMetadataArtifact.SourceSet {
|
||||
return findSourceSet(name)
|
||||
?: throw IllegalArgumentException("No SourceSet with name $name found. Known SourceSets: ${sourceSetsImpl.keys}")
|
||||
}
|
||||
|
||||
override fun findSourceSet(name: String): CompositeMetadataArtifact.SourceSet? =
|
||||
sourceSetsImpl[name]
|
||||
|
||||
|
||||
override fun close() {
|
||||
sourceSetsImpl.values.forEach { it.close() }
|
||||
}
|
||||
}
|
||||
|
||||
private inner class SourceSetImpl(
|
||||
override val artifactHandle: CompositeMetadataArtifact.ArtifactHandle,
|
||||
override val sourceSetName: String,
|
||||
private val artifactFile: ArtifactFile
|
||||
) : CompositeMetadataArtifact.SourceSet, Closeable {
|
||||
|
||||
override val metadataLibrary: CompositeMetadataArtifact.MetadataLibrary? by lazy {
|
||||
/*
|
||||
There are published multiplatform libraries that indeed suppress, disable certain compilations.
|
||||
In this scenario, the sourceSetName might still be mentioned in the artifact, but there will be no
|
||||
metadata-library packaged into the composite artifact.
|
||||
|
||||
In this case, return null
|
||||
*/
|
||||
if (artifactFile.containsDirectory(sourceSetName)) MetadataLibraryImpl(artifactHandle, this, artifactFile) else null
|
||||
}
|
||||
|
||||
override val cinteropMetadataLibraries: List<CompositeMetadataArtifact.CInteropMetadataLibrary> by lazy {
|
||||
val cinteropMetadataDirectory = kotlinProjectStructureMetadata.sourceSetCInteropMetadataDirectory[sourceSetName]
|
||||
?: return@lazy emptyList()
|
||||
|
||||
val cinteropMetadataDirectoryPath = ensureValidZipDirectoryPath(cinteropMetadataDirectory)
|
||||
val cinteropEntries = artifactFile.zip.listDescendants(cinteropMetadataDirectoryPath)
|
||||
|
||||
val cinteropLibraryNames = cinteropEntries.map { entry ->
|
||||
entry.name.removePrefix(cinteropMetadataDirectoryPath).split("/", limit = 2).first()
|
||||
}.toSet()
|
||||
|
||||
cinteropLibraryNames.map { cinteropLibraryName ->
|
||||
CInteropMetadataLibraryImpl(artifactHandle, this, cinteropLibraryName, artifactFile)
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
artifactFile.close()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class MetadataLibraryImpl(
|
||||
override val artifactHandle: CompositeMetadataArtifact.ArtifactHandle,
|
||||
override val sourceSet: CompositeMetadataArtifact.SourceSet,
|
||||
private val artifactFile: ArtifactFile
|
||||
) : CompositeMetadataArtifact.MetadataLibrary {
|
||||
|
||||
override val archiveExtension: String
|
||||
get() = kotlinProjectStructureMetadata.sourceSetBinaryLayout[sourceSet.sourceSetName]?.archiveExtension
|
||||
?: SourceSetMetadataLayout.METADATA.archiveExtension
|
||||
|
||||
/**
|
||||
* Example:
|
||||
* org.jetbrains.sample-sampleLibrary-1.0.0-SNAPSHOT-appleAndLinuxMain.klib
|
||||
*/
|
||||
override val relativeFile: File = File(buildString {
|
||||
append(artifactHandle.moduleDependencyIdentifier)
|
||||
append("-")
|
||||
append(artifactHandle.moduleDependencyVersion)
|
||||
append("-")
|
||||
append(sourceSet.sourceSetName)
|
||||
append(".")
|
||||
append(archiveExtension)
|
||||
})
|
||||
|
||||
override fun copyTo(file: File): Boolean {
|
||||
require(file.extension == archiveExtension) {
|
||||
"Expected file.extension == '$archiveExtension'. Found ${file.extension}"
|
||||
}
|
||||
|
||||
val libraryPath = "${sourceSet.sourceSetName}/"
|
||||
if (!artifactFile.containsDirectory(libraryPath)) return false
|
||||
file.parentFile.mkdirs()
|
||||
artifactFile.zip.copyPartially(file, libraryPath)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private inner class CInteropMetadataLibraryImpl(
|
||||
override val artifactHandle: CompositeMetadataArtifact.ArtifactHandle,
|
||||
override val sourceSet: CompositeMetadataArtifact.SourceSet,
|
||||
override val cinteropLibraryName: String,
|
||||
private val artifact: ArtifactFile,
|
||||
) : CompositeMetadataArtifact.CInteropMetadataLibrary {
|
||||
|
||||
override val archiveExtension: String
|
||||
get() = SourceSetMetadataLayout.KLIB.archiveExtension
|
||||
|
||||
/**
|
||||
* Example:
|
||||
* org.jetbrains.sample-sampleLibrary-1.0.0-SNAPSHOT-appleAndLinuxMain-cinterop/
|
||||
* org.jetbrains.sample_sampleLibrary-cinterop-simple.klib
|
||||
*/
|
||||
override val relativeFile: File = File(buildString {
|
||||
append(artifactHandle.moduleDependencyIdentifier)
|
||||
append("-")
|
||||
append(artifactHandle.moduleDependencyVersion)
|
||||
append("-")
|
||||
append(sourceSet.sourceSetName)
|
||||
append("-cinterop")
|
||||
}).resolve("$cinteropLibraryName.${archiveExtension}")
|
||||
|
||||
override fun copyTo(file: File): Boolean {
|
||||
require(file.extension == archiveExtension) {
|
||||
"Expected 'file.extension == '${SourceSetMetadataLayout.KLIB.archiveExtension}'. Found ${file.extension}"
|
||||
}
|
||||
|
||||
val sourceSetName = sourceSet.sourceSetName
|
||||
val cinteropMetadataDirectory = kotlinProjectStructureMetadata.sourceSetCInteropMetadataDirectory[sourceSetName]
|
||||
?: error("Missing CInteropMetadataDirectory for SourceSet $sourceSetName")
|
||||
val cinteropMetadataDirectoryPath = ensureValidZipDirectoryPath(cinteropMetadataDirectory)
|
||||
|
||||
val libraryPath = "$cinteropMetadataDirectoryPath$cinteropLibraryName/"
|
||||
if (!artifact.containsDirectory(libraryPath)) return false
|
||||
file.parentFile.mkdirs()
|
||||
artifact.zip.copyPartially(file, "$cinteropMetadataDirectoryPath$cinteropLibraryName/")
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to the underlying [zip][file] that only opens the file lazily and keeps references to
|
||||
* all [entries] and infers all potential directory paths (see [directoryPaths] and [containsDirectory])
|
||||
*/
|
||||
private class ArtifactFile(private val file: File) : Closeable {
|
||||
|
||||
private var isClosed = false
|
||||
|
||||
private val lazyZip = lazy {
|
||||
ensureNotClosed()
|
||||
ZipFile(file)
|
||||
}
|
||||
|
||||
val zip: ZipFile get() = lazyZip.value
|
||||
|
||||
val entries: List<ZipEntry> by lazy { zip.entries().toList() }
|
||||
|
||||
/**
|
||||
* All potential directory paths, including inferred directory paths when the [zip] file does
|
||||
* not include directory entries.
|
||||
* @see collectAllDirectoryPaths
|
||||
*/
|
||||
val directoryPaths: Set<String> by lazy { collectAllDirectoryPaths(entries) }
|
||||
|
||||
/**
|
||||
* Check if the underlying [zip] file contains this directory.
|
||||
* Note: This check also works for zip files that did not include directory entries.
|
||||
* This will return true, if any other zip-entry is placed inside this directory [path]
|
||||
*/
|
||||
fun containsDirectory(path: String): Boolean {
|
||||
val validPath = ensureValidZipDirectoryPath(path)
|
||||
if (zip.getEntry(validPath) != null) return true
|
||||
return validPath in directoryPaths
|
||||
}
|
||||
|
||||
private fun ensureNotClosed() {
|
||||
if (isClosed) throw IOException("LazyZipFile is already closed!")
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
isClosed = true
|
||||
if (lazyZip.isInitialized()) {
|
||||
lazyZip.value.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip files are not **forced** to include entries for directories.
|
||||
* In order to do preliminary checks, if some directory is present in Zip Files it is
|
||||
* often useful to infer the directories included in any Zip File by looking into file entries
|
||||
* and inferring their directories.
|
||||
*/
|
||||
private fun collectAllDirectoryPaths(entries: List<ZipEntry>): Set<String> {
|
||||
/*
|
||||
The 'root' directory is represented as empty String in ZipFile
|
||||
*/
|
||||
val set = hashSetOf("")
|
||||
|
||||
entries.forEach { entry ->
|
||||
if (entry.isDirectory) {
|
||||
set.add(entry.name)
|
||||
return@forEach
|
||||
}
|
||||
|
||||
/* Collect all 'intermediate' directories found by looking at the files path */
|
||||
val pathParts = entry.name.split("/")
|
||||
pathParts.runningReduce { currentPath, nextPart ->
|
||||
set.add("$currentPath/")
|
||||
"$currentPath/$nextPart"
|
||||
}
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* 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.gradle.kotlin.dsl.support.unzipTo
|
||||
import org.gradle.kotlin.dsl.support.zipTo
|
||||
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 org.junit.Rule
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import java.io.File
|
||||
import kotlin.test.*
|
||||
|
||||
class CompositeMetadataArtifactTest {
|
||||
|
||||
@get:Rule
|
||||
val temporaryFolder = TemporaryFolder()
|
||||
|
||||
@Test
|
||||
fun `empty jar - contains no metadataLibrary and no cinteropMetadataLibraries`() {
|
||||
val primaryArtifactContent = temporaryFolder.newFolder()
|
||||
val primaryArtifactFile = temporaryFolder.newFile("metadata.jar")
|
||||
zipTo(primaryArtifactFile, primaryArtifactContent)
|
||||
assertTrue(primaryArtifactFile.isFile, "Expected primaryArtifactFile.isFile")
|
||||
|
||||
val metadataArtifact = CompositeMetadataArtifactImpl(
|
||||
moduleDependencyIdentifier = ModuleDependencyIdentifier("test-group", "test-module"),
|
||||
moduleDependencyVersion = "1.0.0",
|
||||
kotlinProjectStructureMetadata = createProjectStructureMetadata(
|
||||
sourceSetNames = mutableSetOf("testSourceSetName"),
|
||||
sourceSetBinaryLayout = mapOf("testSourceSetName" to KLIB),
|
||||
sourceSetCInteropMetadataDirectory = mapOf("testSourceSetName" to "cinterop/testSourceSetName")
|
||||
),
|
||||
primaryArtifactFile = primaryArtifactFile,
|
||||
hostSpecificArtifactFilesBySourceSetName = emptyMap()
|
||||
)
|
||||
|
||||
|
||||
metadataArtifact.read { artifactHandle ->
|
||||
if (artifactHandle.sourceSets.size != 1) fail("Expected one SourceSet in metadataArtifact")
|
||||
val sourceSet = artifactHandle.sourceSets.first()
|
||||
assertEquals("testSourceSetName", sourceSet.sourceSetName)
|
||||
assertNull(sourceSet.metadataLibrary, "Expected no 'metadataLibrary' listed for SourceSet")
|
||||
|
||||
if (sourceSet.cinteropMetadataLibraries.isNotEmpty()) {
|
||||
fail(
|
||||
"Expected no 'cinteropMetadataLibraries' in 'testSourceSet'. " +
|
||||
"Found ${sourceSet.cinteropMetadataLibraries.map { it.cinteropLibraryName }}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `stub metadata library - can be unzipped`() {
|
||||
val testSourceSetName = "testSourceSetName"
|
||||
val primaryArtifactContent = temporaryFolder.newFolder()
|
||||
val stubFile = primaryArtifactContent.resolve(testSourceSetName).resolve("stub.txt")
|
||||
stubFile.parentFile.mkdirs()
|
||||
stubFile.writeText("stub!")
|
||||
|
||||
val primaryArtifactFile = temporaryFolder.newFile("metadata.jar")
|
||||
zipTo(primaryArtifactFile, primaryArtifactContent)
|
||||
assertTrue(primaryArtifactFile.isFile, "Expected primaryArtifactFile.isFile")
|
||||
|
||||
val metadataArtifact = CompositeMetadataArtifactImpl(
|
||||
moduleDependencyIdentifier = ModuleDependencyIdentifier("test-group", "test-module"),
|
||||
moduleDependencyVersion = "1.0.0",
|
||||
kotlinProjectStructureMetadata = createProjectStructureMetadata(
|
||||
sourceSetBinaryLayout = mapOf(testSourceSetName to KLIB),
|
||||
sourceSetCInteropMetadataDirectory = emptyMap(),
|
||||
),
|
||||
primaryArtifactFile = primaryArtifactFile,
|
||||
hostSpecificArtifactFilesBySourceSetName = emptyMap()
|
||||
)
|
||||
|
||||
metadataArtifact.read { artifactHandle ->
|
||||
if (artifactHandle.sourceSets.size != 1)
|
||||
fail("Expected exactly one SourceSet in ${artifactHandle.sourceSets.map { it.sourceSetName }}")
|
||||
|
||||
val sourceSet = artifactHandle.getSourceSet(testSourceSetName)
|
||||
val metadataOutputDirectory = temporaryFolder.newFolder()
|
||||
val metadataFile = metadataOutputDirectory.resolve("testSourceSet.klib")
|
||||
|
||||
val metadataLibrary = sourceSet.metadataLibrary ?: fail("Missing metadataLibrary for ${sourceSet.sourceSetName}")
|
||||
assertTrue(metadataLibrary.copyTo(metadataFile), "Expected 'copyTo' to perform copy action")
|
||||
assertTrue(metadataFile.isFile)
|
||||
|
||||
val unzippedMetadataFile = metadataOutputDirectory.resolve("unzipped")
|
||||
unzipTo(unzippedMetadataFile, metadataFile)
|
||||
|
||||
assertEquals(setOf(unzippedMetadataFile.resolve("stub.txt")), unzippedMetadataFile.listFiles().orEmpty().toSet())
|
||||
assertEquals("stub!", unzippedMetadataFile.resolve("stub.txt").readText())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `empty jar - returns no cinteropMetadataLibraries`() {
|
||||
val primaryArtifactContent = temporaryFolder.newFolder()
|
||||
val primaryArtifactFile = temporaryFolder.newFile("metadata.jar")
|
||||
zipTo(primaryArtifactFile, primaryArtifactContent)
|
||||
assertTrue(primaryArtifactFile.isFile, "Expected primaryArtifactFile.isFile")
|
||||
|
||||
val metadataArtifact = CompositeMetadataArtifactImpl(
|
||||
moduleDependencyIdentifier = ModuleDependencyIdentifier("test-group", "test-module"),
|
||||
moduleDependencyVersion = "1.0.0",
|
||||
kotlinProjectStructureMetadata = createProjectStructureMetadata(
|
||||
sourceSetNames = setOf("testSourceSetName")
|
||||
),
|
||||
primaryArtifactFile = primaryArtifactFile,
|
||||
hostSpecificArtifactFilesBySourceSetName = emptyMap()
|
||||
)
|
||||
|
||||
metadataArtifact.read { artifactHandle ->
|
||||
val sourceSet = artifactHandle.getSourceSet("testSourceSetName")
|
||||
assertEquals(listOf(sourceSet), artifactHandle.sourceSets)
|
||||
|
||||
assertEquals(emptyList(), sourceSet.cinteropMetadataLibraries, "Expected empty cinteropMetadataLibraries")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `copy metadataLibrary`() {
|
||||
/* Setup Artifact content */
|
||||
val primaryArtifactContent = temporaryFolder.newFolder()
|
||||
|
||||
primaryArtifactContent.resolve("sourceSetA/sourceSetAStub1.txt")
|
||||
.withParentDirectoriesCreated()
|
||||
.writeText("Content of sourceSetA stub1")
|
||||
|
||||
primaryArtifactContent.resolve("sourceSetA/nested/sourceSetAStub2.txt")
|
||||
.withParentDirectoriesCreated()
|
||||
.writeText("Content of sourceSetB stub2")
|
||||
|
||||
primaryArtifactContent.resolve("sourceSetB/sourceSetBStub1.txt")
|
||||
.withParentDirectoriesCreated()
|
||||
.writeText("Content of sourceSetB stub1")
|
||||
|
||||
primaryArtifactContent.resolve("sourceSetB/nested/sourceSetBStub2.txt")
|
||||
.withParentDirectoriesCreated()
|
||||
.writeText("Content of sourceSetB stub2")
|
||||
|
||||
/* Create metadata jar */
|
||||
val primaryArtifactFile = temporaryFolder.newFile("metadata.jar")
|
||||
zipTo(primaryArtifactFile, primaryArtifactContent)
|
||||
|
||||
val metadataArtifact = CompositeMetadataArtifactImpl(
|
||||
moduleDependencyIdentifier = ModuleDependencyIdentifier("test-group", "test-module"),
|
||||
moduleDependencyVersion = "1.0.0",
|
||||
kotlinProjectStructureMetadata = createProjectStructureMetadata(
|
||||
sourceSetBinaryLayout = mapOf("sourceSetA" to KLIB, "sourceSetB" to METADATA)
|
||||
),
|
||||
primaryArtifactFile = primaryArtifactFile,
|
||||
hostSpecificArtifactFilesBySourceSetName = emptyMap()
|
||||
)
|
||||
|
||||
metadataArtifact.read { artifactHandle ->
|
||||
val metadataOutputDirectory = temporaryFolder.newFolder()
|
||||
|
||||
/* Extract and assert sourceSetA */
|
||||
artifactHandle.getSourceSet("sourceSetA").also { sourceSetA ->
|
||||
val sourceSetAMetadataFile = metadataOutputDirectory.resolve("sourceSetA.klib")
|
||||
assertNotNull(sourceSetA.metadataLibrary).copyTo(sourceSetAMetadataFile)
|
||||
assertTrue(sourceSetAMetadataFile.isFile, "Expected sourceSetAMetadataFile.isFile")
|
||||
assertEquals(
|
||||
KLIB.archiveExtension, sourceSetAMetadataFile.extension,
|
||||
"Expected correct archiveExtension for extracted sourceSetA"
|
||||
)
|
||||
assertZipContentEquals(
|
||||
temporaryFolder,
|
||||
primaryArtifactContent.resolve("sourceSetA"), sourceSetAMetadataFile,
|
||||
"Expected correct content of extracted 'sourceSetA'"
|
||||
)
|
||||
}
|
||||
|
||||
/* Extract and assert sourceSetB */
|
||||
artifactHandle.getSourceSet("sourceSetB").also { sourceSetB ->
|
||||
val sourceSetBMetadataFile = metadataOutputDirectory.resolve("sourceSetB.jar")
|
||||
assertNotNull(sourceSetB.metadataLibrary).copyTo(sourceSetBMetadataFile)
|
||||
assertTrue(sourceSetBMetadataFile.isFile, "Expected sourceSetBMetadataFile.isFile")
|
||||
assertEquals(
|
||||
METADATA.archiveExtension, sourceSetBMetadataFile.extension,
|
||||
"Expected correct archiveExtension for extracted sourceSetB"
|
||||
)
|
||||
assertZipContentEquals(
|
||||
temporaryFolder,
|
||||
primaryArtifactContent.resolve("sourceSetB"), sourceSetBMetadataFile,
|
||||
"Expected correct content of extracted 'sourceSetA'"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `copy cinteropMetadataLibraries`() {
|
||||
/* Setup Artifact content */
|
||||
val primaryArtifactContent = temporaryFolder.newFolder()
|
||||
|
||||
primaryArtifactContent.resolve("sourceSetA-cinterop/interopA0/stub0")
|
||||
.withParentDirectoriesCreated()
|
||||
.writeText("stub0 content")
|
||||
|
||||
primaryArtifactContent.resolve("sourceSetA-cinterop/interopA0/nested/stub1")
|
||||
.withParentDirectoriesCreated()
|
||||
.writeText("stub1 content")
|
||||
|
||||
primaryArtifactContent.resolve("sourceSetA-cinterop/interopA1/stub2")
|
||||
.withParentDirectoriesCreated()
|
||||
.writeText("stub2 content")
|
||||
|
||||
primaryArtifactContent.resolve("nested/sourceSetB/interops/interopB0/stub3")
|
||||
.withParentDirectoriesCreated()
|
||||
.writeText("stub3 content")
|
||||
|
||||
/* Create metadata jar */
|
||||
val primaryArtifactFile = temporaryFolder.newFile("metadata.jar")
|
||||
zipTo(primaryArtifactFile, primaryArtifactContent)
|
||||
|
||||
val metadataArtifact = CompositeMetadataArtifactImpl(
|
||||
moduleDependencyIdentifier = ModuleDependencyIdentifier("test-group", "test-module"),
|
||||
moduleDependencyVersion = "1.0.0",
|
||||
kotlinProjectStructureMetadata = createProjectStructureMetadata(
|
||||
sourceSetCInteropMetadataDirectory = mapOf(
|
||||
"sourceSetA" to "sourceSetA-cinterop",
|
||||
"sourceSetB" to "nested/sourceSetB/interops/"
|
||||
)
|
||||
),
|
||||
primaryArtifactFile = primaryArtifactFile,
|
||||
hostSpecificArtifactFilesBySourceSetName = emptyMap()
|
||||
)
|
||||
|
||||
metadataArtifact.read { artifactHandle ->
|
||||
/* Assertions on sourceSetA */
|
||||
artifactHandle.getSourceSet("sourceSetA").also { sourceSetA ->
|
||||
val sourceSetAOutputDirectory = temporaryFolder.newFolder()
|
||||
val sourceSetAInteropMetadataFiles = sourceSetA.cinteropMetadataLibraries.map { cinteropLibrary ->
|
||||
sourceSetAOutputDirectory.resolve("${cinteropLibrary.cinteropLibraryName}.klib").also { file ->
|
||||
cinteropLibrary.copyTo(file)
|
||||
}
|
||||
}
|
||||
assertEquals(2, sourceSetAInteropMetadataFiles.size, "Expected 2 cinterops in sourceSetA")
|
||||
|
||||
/* Assertions on interopA0 */
|
||||
run {
|
||||
val interopA0MetadataFile = sourceSetAInteropMetadataFiles.firstOrNull { it.name == "interopA0.klib" }
|
||||
?: fail("Failed to find 'interopA0.klib'")
|
||||
assertZipContentEquals(
|
||||
temporaryFolder,
|
||||
primaryArtifactContent.resolve("sourceSetA-cinterop/interopA0"), interopA0MetadataFile,
|
||||
"Expected correct content for extracted 'interopA0'"
|
||||
)
|
||||
}
|
||||
|
||||
/* Assertions on interopA1 */
|
||||
run {
|
||||
val interopA1MetadataFile = sourceSetAInteropMetadataFiles.firstOrNull { it.name == "interopA1.klib" }
|
||||
?: fail("Failed to find 'interopA1.klib")
|
||||
assertZipContentEquals(
|
||||
temporaryFolder,
|
||||
primaryArtifactContent.resolve("sourceSetA-cinterop/interopA1"), interopA1MetadataFile,
|
||||
"Expected correct content for extracted 'interopA1'"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* Assertions on sourceSetB */
|
||||
artifactHandle.getSourceSet("sourceSetB").also { sourceSetB ->
|
||||
val sourceSetBOutputDirectory = temporaryFolder.newFolder()
|
||||
val sourceSetBInteropMetadataFiles = sourceSetB.cinteropMetadataLibraries.map { cinteropLibrary ->
|
||||
sourceSetBOutputDirectory.resolve("${cinteropLibrary.cinteropLibraryName}.klib").also { file ->
|
||||
cinteropLibrary.copyTo(file)
|
||||
}
|
||||
}
|
||||
assertEquals(1, sourceSetBInteropMetadataFiles.size, "Expected only one cinterop in sourceSetB")
|
||||
val interopB0MetadataFile = sourceSetBInteropMetadataFiles.firstOrNull { it.name == "interopB0.klib" }
|
||||
?: fail("Failed to find 'interopB0.klib'")
|
||||
assertZipContentEquals(
|
||||
temporaryFolder,
|
||||
primaryArtifactContent.resolve("nested/sourceSetB/interops/interopB0"), interopB0MetadataFile,
|
||||
"Expected correct content for extracted 'interopB0'"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createProjectStructureMetadata(
|
||||
sourceSetNamesByVariantName: Map<String, Set<String>> = emptyMap(),
|
||||
sourceSetsDependsOnRelation: Map<String, Set<String>> = emptyMap(),
|
||||
sourceSetCInteropMetadataDirectory: Map<String, String> = emptyMap(),
|
||||
sourceSetBinaryLayout: Map<String, SourceSetMetadataLayout> = emptyMap(),
|
||||
sourceSetModuleDependencies: Map<String, Set<ModuleDependencyIdentifier>> = emptyMap(),
|
||||
hostSpecificSourceSets: Set<String> = emptySet(),
|
||||
sourceSetNames: Set<String> = hostSpecificSourceSets +
|
||||
sourceSetNamesByVariantName.values.flatten() +
|
||||
sourceSetsDependsOnRelation.keys +
|
||||
sourceSetCInteropMetadataDirectory.keys +
|
||||
sourceSetBinaryLayout.keys +
|
||||
sourceSetModuleDependencies.keys,
|
||||
isPublishedAsRoot: Boolean = true,
|
||||
): KotlinProjectStructureMetadata {
|
||||
return KotlinProjectStructureMetadata(
|
||||
sourceSetNamesByVariantName = sourceSetNamesByVariantName,
|
||||
sourceSetsDependsOnRelation = sourceSetsDependsOnRelation,
|
||||
sourceSetBinaryLayout = sourceSetBinaryLayout,
|
||||
sourceSetCInteropMetadataDirectory = sourceSetCInteropMetadataDirectory,
|
||||
sourceSetModuleDependencies = sourceSetModuleDependencies,
|
||||
hostSpecificSourceSets = hostSpecificSourceSets,
|
||||
sourceSetNames = sourceSetNames,
|
||||
isPublishedAsRoot = isPublishedAsRoot
|
||||
)
|
||||
}
|
||||
|
||||
private fun File.withParentDirectoriesCreated(): File = apply { parentFile.mkdirs() }
|
||||
Reference in New Issue
Block a user