[Gradle][MPP] Extract CompositeMetadataArtifact.ArtifactContent

... into its own top level entity called CompositeMetadataArtifactContent.

This commit also refines naming os the APIs and provides
additional documentation.

^KT-48135 Verification Pending
This commit is contained in:
Sebastian Sellmair
2022-09-21 12:55:40 +02:00
committed by Space
parent 4935026b2c
commit 929750011a
6 changed files with 127 additions and 111 deletions
@@ -37,12 +37,12 @@ internal class IdeaKpmMetadataBinaryDependencyResolver(
return metadataProvider.read { artifactContent ->
resolution.allVisibleSourceSetNames.mapNotNull { visibleFragmentName ->
val sourceSet = artifactContent.findSourceSet(visibleFragmentName) ?: return@mapNotNull null
val metadataLibrary = sourceSet.metadataLibrary ?: return@mapNotNull null
val sourceSetContent = artifactContent.findSourceSet(visibleFragmentName) ?: return@mapNotNull null
val metadataBinary = sourceSetContent.metadataBinary ?: return@mapNotNull null
val libraryFile = fragment.project.kotlinTransformedMetadataLibraryDirectoryForIde
.resolve(metadataLibrary.relativeFile)
.apply { if (!isFile) metadataLibrary.copyTo(this) }
.resolve(metadataBinary.relativeFile)
.apply { if (!isFile) metadataBinary.copyTo(this) }
IdeaKpmResolvedBinaryDependencyImpl(
binaryType = IdeaKpmDependency.CLASSPATH_BINARY_TYPE,
@@ -9,70 +9,91 @@ import java.io.Closeable
import java.io.File
internal interface CompositeMetadataArtifact {
val moduleDependencyIdentifier: ModuleDependencyIdentifier
val moduleDependencyVersion: String
/**
* Provides access to the actual content provided by this artifact.
* Note: [CompositeMetadataArtifactContent] is [Closeable] and might actively open Files on access.
* A [Closeable.close] call is required.
*
* Alternatively use the [read] function instead.
*/
fun open(): CompositeMetadataArtifactContent
/**
* Safe shortcut function for opening and reading the content of this artifact.
* The [CompositeMetadataArtifactContent] will be closed after the [action] executed.
*/
fun <T> read(action: (artifactContent: CompositeMetadataArtifactContent) -> T): T {
return open().use(action)
}
}
internal interface CompositeMetadataArtifactContent : Closeable {
/**
* Back reference to the [CompositeMetadataArtifact] that opened this [CompositeMetadataArtifactContent]
*/
val containingArtifact: CompositeMetadataArtifact
val sourceSets: List<SourceSetContent>
fun getSourceSet(name: String): SourceSetContent
fun findSourceSet(name: String): SourceSetContent?
/**
* Represents a SourceSet packaged into the [CompositeMetadataArtifact]
*/
interface SourceSetContent {
/**
* Back reference to the [CompositeMetadataArtifactContent] that contains this [SourceSetContent]
*/
val containingArtifactContent: CompositeMetadataArtifactContent
val sourceSetName: String
val metadataBinary: MetadataBinary?
val cinteropMetadataBinaries: List<CInteropMetadataBinary>
}
interface Binary {
/**
* Back reference to the [SourceSetContent] that contains this [Binary]
*/
val containingSourceSetContent: SourceSetContent
interface Library {
val artifactContent: ArtifactContent
val sourceSet: SourceSet
val archiveExtension: String
val checksum: String
/**
* The proposed file-output path.
* This can actually include several path parts if the [Library] requires additional scoping (e.g. [CInteropMetadataLibrary]s
* This can actually include several path parts if the [Binary] requires additional scoping (e.g. [CInteropMetadataBinary]s
* need to be put into another folder)
*/
val relativeFile: File
val checksum: String
/**
* Copies the content of this [Library] directly into the given [file].
* Copies the content of this [Binary] 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.
* Copies the content of this [Binary] 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]
* Represents a Kotlin Metadata Binary produced by compiling the contained [containingSourceSetContent]
*/
interface CInteropMetadataLibrary : Library {
interface MetadataBinary : Binary
/**
* Represents a CInterop Metadata Binary, produced by the commonizer and attached to the [containingSourceSetContent]
*/
interface CInteropMetadataBinary : Binary {
val cinteropLibraryName: String
}
/**
* Represents a SourceSet packaged into the [CompositeMetadataArtifact]
*/
interface SourceSet {
val artifactContent: ArtifactContent
val sourceSetName: String
val metadataLibrary: MetadataLibrary?
val cinteropMetadataLibraries: List<CInteropMetadataLibrary>
}
interface ArtifactContent : 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(): ArtifactContent
fun <T> read(action: (artifactContent: ArtifactContent) -> T): T {
return open().use(action)
}
}
}
@@ -26,32 +26,29 @@ internal class CompositeMetadataArtifactImpl(
private val hostSpecificArtifactFilesBySourceSetName: Map<String, File>
) : CompositeMetadataArtifact {
override fun open(): CompositeMetadataArtifact.ArtifactContent {
return HandlerImpl()
override fun open(): CompositeMetadataArtifactContent {
return CompositeMetadataArtifactContentImpl()
}
inner class HandlerImpl : CompositeMetadataArtifact.ArtifactContent {
inner class CompositeMetadataArtifactContentImpl : CompositeMetadataArtifactContent {
override val moduleDependencyIdentifier: ModuleDependencyIdentifier
get() = this@CompositeMetadataArtifactImpl.moduleDependencyIdentifier
override val moduleDependencyVersion: String
get() = this@CompositeMetadataArtifactImpl.moduleDependencyVersion
override val containingArtifact: CompositeMetadataArtifact
get() = this@CompositeMetadataArtifactImpl
/* 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))
SourceSetContentImpl(this, sourceSetName, ArtifactFile(hostSpecificArtifactFilesBySourceSetName[sourceSetName] ?: primaryArtifactFile))
}
override val sourceSets: List<CompositeMetadataArtifact.SourceSet> =
override val sourceSets: List<CompositeMetadataArtifactContent.SourceSetContent> =
sourceSetsImpl.values.toList()
override fun getSourceSet(name: String): CompositeMetadataArtifact.SourceSet {
override fun getSourceSet(name: String): CompositeMetadataArtifactContent.SourceSetContent {
return findSourceSet(name)
?: throw IllegalArgumentException("No SourceSet with name $name found. Known SourceSets: ${sourceSetsImpl.keys}")
}
override fun findSourceSet(name: String): CompositeMetadataArtifact.SourceSet? =
override fun findSourceSet(name: String): CompositeMetadataArtifactContent.SourceSetContent? =
sourceSetsImpl[name]
@@ -60,13 +57,13 @@ internal class CompositeMetadataArtifactImpl(
}
}
private inner class SourceSetImpl(
override val artifactContent: CompositeMetadataArtifact.ArtifactContent,
private inner class SourceSetContentImpl(
override val containingArtifactContent: CompositeMetadataArtifactContent,
override val sourceSetName: String,
private val artifactFile: ArtifactFile
) : CompositeMetadataArtifact.SourceSet, Closeable {
) : CompositeMetadataArtifactContent.SourceSetContent, Closeable {
override val metadataLibrary: CompositeMetadataArtifact.MetadataLibrary? by lazy {
override val metadataBinary: CompositeMetadataArtifactContent.MetadataBinary? 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
@@ -74,10 +71,10 @@ internal class CompositeMetadataArtifactImpl(
In this case, return null
*/
if (artifactFile.containsDirectory(sourceSetName)) MetadataLibraryImpl(artifactContent, this, artifactFile) else null
if (artifactFile.containsDirectory(sourceSetName)) MetadataBinaryImpl(this, artifactFile) else null
}
override val cinteropMetadataLibraries: List<CompositeMetadataArtifact.CInteropMetadataLibrary> by lazy {
override val cinteropMetadataBinaries: List<CompositeMetadataArtifactContent.CInteropMetadataBinary> by lazy {
val cinteropMetadataDirectory = kotlinProjectStructureMetadata.sourceSetCInteropMetadataDirectory[sourceSetName]
?: return@lazy emptyList()
@@ -89,7 +86,7 @@ internal class CompositeMetadataArtifactImpl(
}.toSet()
cinteropLibraryNames.map { cinteropLibraryName ->
CInteropMetadataLibraryImpl(artifactContent, this, cinteropLibraryName, artifactFile)
CInteropMetadataBinaryImpl(this, cinteropLibraryName, artifactFile)
}
}
@@ -98,14 +95,13 @@ internal class CompositeMetadataArtifactImpl(
}
}
private inner class MetadataLibraryImpl(
override val artifactContent: CompositeMetadataArtifact.ArtifactContent,
override val sourceSet: CompositeMetadataArtifact.SourceSet,
private inner class MetadataBinaryImpl(
override val containingSourceSetContent: CompositeMetadataArtifactContent.SourceSetContent,
private val artifactFile: ArtifactFile
) : CompositeMetadataArtifact.MetadataLibrary {
) : CompositeMetadataArtifactContent.MetadataBinary {
override val archiveExtension: String
get() = kotlinProjectStructureMetadata.sourceSetBinaryLayout[sourceSet.sourceSetName]?.archiveExtension
get() = kotlinProjectStructureMetadata.sourceSetBinaryLayout[containingSourceSetContent.sourceSetName]?.archiveExtension
?: SourceSetMetadataLayout.METADATA.archiveExtension
override val checksum: String
@@ -116,13 +112,13 @@ internal class CompositeMetadataArtifactImpl(
* org.jetbrains.sample-sampleLibrary-1.0.0-SNAPSHOT-appleAndLinuxMain-Vk5pxQ.klib
*/
override val relativeFile: File = File(buildString {
append(artifactContent.moduleDependencyIdentifier)
append(containingSourceSetContent.containingArtifactContent.containingArtifact.moduleDependencyIdentifier)
append("-")
append(artifactContent.moduleDependencyVersion)
append(containingSourceSetContent.containingArtifactContent.containingArtifact.moduleDependencyVersion)
append("-")
append(sourceSet.sourceSetName)
append(containingSourceSetContent.sourceSetName)
append("-")
append(this@MetadataLibraryImpl.checksum)
append(this@MetadataBinaryImpl.checksum)
append(".")
append(archiveExtension)
})
@@ -132,7 +128,7 @@ internal class CompositeMetadataArtifactImpl(
"Expected file.extension == '$archiveExtension'. Found ${file.extension}"
}
val libraryPath = "${sourceSet.sourceSetName}/"
val libraryPath = "${containingSourceSetContent.sourceSetName}/"
if (!artifactFile.containsDirectory(libraryPath)) return false
file.parentFile.mkdirs()
artifactFile.zip.copyPartially(file, libraryPath)
@@ -141,12 +137,11 @@ internal class CompositeMetadataArtifactImpl(
}
}
private inner class CInteropMetadataLibraryImpl(
override val artifactContent: CompositeMetadataArtifact.ArtifactContent,
override val sourceSet: CompositeMetadataArtifact.SourceSet,
private inner class CInteropMetadataBinaryImpl(
override val containingSourceSetContent: CompositeMetadataArtifactContent.SourceSetContent,
override val cinteropLibraryName: String,
private val artifactFile: ArtifactFile,
) : CompositeMetadataArtifact.CInteropMetadataLibrary {
) : CompositeMetadataArtifactContent.CInteropMetadataBinary {
override val archiveExtension: String
get() = SourceSetMetadataLayout.KLIB.archiveExtension
@@ -160,11 +155,11 @@ internal class CompositeMetadataArtifactImpl(
* org.jetbrains.sample_sampleLibrary-cinterop-simple-Vk5pxQ.klib
*/
override val relativeFile: File = File(buildString {
append(artifactContent.moduleDependencyIdentifier)
append(containingSourceSetContent.containingArtifactContent.containingArtifact.moduleDependencyIdentifier)
append("-")
append(artifactContent.moduleDependencyVersion)
append(containingSourceSetContent.containingArtifactContent.containingArtifact.moduleDependencyVersion)
append("-")
append(sourceSet.sourceSetName)
append(containingSourceSetContent.sourceSetName)
append("-cinterop")
}).resolve("$cinteropLibraryName-${this.checksum}.${archiveExtension}")
@@ -173,7 +168,7 @@ internal class CompositeMetadataArtifactImpl(
"Expected 'file.extension == '${SourceSetMetadataLayout.KLIB.archiveExtension}'. Found ${file.extension}"
}
val sourceSetName = sourceSet.sourceSetName
val sourceSetName = containingSourceSetContent.sourceSetName
val cinteropMetadataDirectory = kotlinProjectStructureMetadata.sourceSetCInteropMetadataDirectory[sourceSetName]
?: error("Missing CInteropMetadataDirectory for SourceSet $sourceSetName")
val cinteropMetadataDirectoryPath = ensureValidZipDirectoryPath(cinteropMetadataDirectory)
@@ -62,12 +62,12 @@ private fun transformMetadataLibrariesForIde(
): Map<String /* visibleSourceSetName */, Iterable<File>> {
return compositeMetadataArtifact.read { artifactContent ->
resolution.visibleSourceSetNamesExcludingDependsOn.mapNotNull { visibleSourceSetName ->
val sourceSet = artifactContent.findSourceSet(visibleSourceSetName) ?: return@mapNotNull null
val sourceSetMetadataLibrary = sourceSet.metadataLibrary ?: return@mapNotNull null
val metadataLibraryOutputFile = baseOutputDirectory.resolve(sourceSetMetadataLibrary.relativeFile)
val sourceSetContent = artifactContent.findSourceSet(visibleSourceSetName) ?: return@mapNotNull null
val sourceSetMetadataBinary = sourceSetContent.metadataBinary ?: return@mapNotNull null
val metadataLibraryOutputFile = baseOutputDirectory.resolve(sourceSetMetadataBinary.relativeFile)
metadataLibraryOutputFile.parentFile.mkdirs()
if (!metadataLibraryOutputFile.exists()) {
sourceSetMetadataLibrary.copyTo(metadataLibraryOutputFile)
sourceSetMetadataBinary.copyTo(metadataLibraryOutputFile)
if (!metadataLibraryOutputFile.exists()) return@mapNotNull null
}
@@ -84,12 +84,12 @@ private fun transformMetadataLibrariesForBuild(
): Set<File> {
return compositeMetadataArtifact.read { artifactContent ->
resolution.visibleSourceSetNamesExcludingDependsOn.mapNotNull { visibleSourceSetName ->
val sourceSet = artifactContent.findSourceSet(visibleSourceSetName) ?: return@mapNotNull null
val metadataLibrary = sourceSet.metadataLibrary ?: return@mapNotNull null
val metadataLibraryFile = outputDirectory.resolve(metadataLibrary.relativeFile)
val sourceSetContent = artifactContent.findSourceSet(visibleSourceSetName) ?: return@mapNotNull null
val metadataBinary = sourceSetContent.metadataBinary ?: return@mapNotNull null
val metadataLibraryFile = outputDirectory.resolve(metadataBinary.relativeFile)
if (materializeFiles) {
metadataLibraryFile.parentFile?.mkdirs()
metadataLibrary.copyTo(metadataLibraryFile)
metadataBinary.copyTo(metadataLibraryFile)
}
metadataLibraryFile
}
@@ -141,8 +141,8 @@ internal open class CInteropMetadataDependencyTransformationTask @Inject constru
chooseVisibleSourceSets.metadataProvider.read { artifactContent ->
chooseVisibleSourceSets.visibleSourceSetsProvidingCInterops
.mapNotNull { visibleSourceSetName -> artifactContent.findSourceSet(visibleSourceSetName) }
.flatMap { sourceSet -> sourceSet.cinteropMetadataLibraries }
.map { cInteropMetadataLibrary -> outputDirectory.resolve(cInteropMetadataLibrary.relativeFile) }
.flatMap { sourceSetContent -> sourceSetContent.cinteropMetadataBinaries }
.map { cInteropMetadataBinary -> outputDirectory.resolve(cInteropMetadataBinary.relativeFile) }
}
}.toSet()
}
@@ -215,8 +215,8 @@ internal open class CInteropMetadataDependencyTransformationTask @Inject constru
is ArtifactMetadataProvider -> chooseVisibleSourceSets.metadataProvider.read { artifactContent ->
chooseVisibleSourceSets.visibleSourceSetsProvidingCInterops
.mapNotNull { visibleSourceSetName -> artifactContent.findSourceSet(visibleSourceSetName) }
.flatMap { sourceSet -> sourceSet.cinteropMetadataLibraries }
.forEach { cInteropMetadataLibrary -> cInteropMetadataLibrary.copyIntoDirectory(outputDirectory) }
.flatMap { sourceSetContent -> sourceSetContent.cinteropMetadataBinaries }
.forEach { cInteropMetadataBinary -> cInteropMetadataBinary.copyIntoDirectory(outputDirectory) }
}
}
@@ -23,7 +23,7 @@ class CompositeMetadataArtifactTest {
val temporaryFolder = TemporaryFolder()
@Test
fun `empty jar - contains no metadataLibrary and no cinteropMetadataLibraries`() {
fun `empty jar - contains no metadataBinary and no cinteropMetadataBinaries`() {
val primaryArtifactContent = temporaryFolder.newFolder()
val primaryArtifactFile = temporaryFolder.newFile("metadata.jar")
zipTo(primaryArtifactFile, primaryArtifactContent)
@@ -44,14 +44,14 @@ class CompositeMetadataArtifactTest {
metadataArtifact.read { artifactContent ->
if (artifactContent.sourceSets.size != 1) fail("Expected one SourceSet in metadataArtifact")
val sourceSet = artifactContent.sourceSets.first()
assertEquals("testSourceSetName", sourceSet.sourceSetName)
assertNull(sourceSet.metadataLibrary, "Expected no 'metadataLibrary' listed for SourceSet")
val sourceSetContent = artifactContent.sourceSets.first()
assertEquals("testSourceSetName", sourceSetContent.sourceSetName)
assertNull(sourceSetContent.metadataBinary, "Expected no 'metadataBinary' listed for SourceSet")
if (sourceSet.cinteropMetadataLibraries.isNotEmpty()) {
if (sourceSetContent.cinteropMetadataBinaries.isNotEmpty()) {
fail(
"Expected no 'cinteropMetadataLibraries' in 'testSourceSet'. " +
"Found ${sourceSet.cinteropMetadataLibraries.map { it.cinteropLibraryName }}"
"Expected no 'cinteropMetadataBinaries' in 'testSourceSet'. " +
"Found ${sourceSetContent.cinteropMetadataBinaries.map { it.cinteropLibraryName }}"
)
}
}
@@ -88,8 +88,8 @@ class CompositeMetadataArtifactTest {
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")
val metadataBinary = sourceSet.metadataBinary ?: fail("Missing metadataBinary for ${sourceSet.sourceSetName}")
assertTrue(metadataBinary.copyTo(metadataFile), "Expected 'copyTo' to perform copy action")
assertTrue(metadataFile.isFile)
val unzippedMetadataFile = metadataOutputDirectory.resolve("unzipped")
@@ -101,7 +101,7 @@ class CompositeMetadataArtifactTest {
}
@Test
fun `empty jar - returns no cinteropMetadataLibraries`() {
fun `empty jar - returns no cinteropMetadataBinaries`() {
val primaryArtifactContent = temporaryFolder.newFolder()
val primaryArtifactFile = temporaryFolder.newFile("metadata.jar")
zipTo(primaryArtifactFile, primaryArtifactContent)
@@ -121,12 +121,12 @@ class CompositeMetadataArtifactTest {
val sourceSet = artifactContent.getSourceSet("testSourceSetName")
assertEquals(listOf(sourceSet), artifactContent.sourceSets)
assertEquals(emptyList(), sourceSet.cinteropMetadataLibraries, "Expected empty cinteropMetadataLibraries")
assertEquals(emptyList(), sourceSet.cinteropMetadataBinaries, "Expected empty cinteropMetadataBinaries")
}
}
@Test
fun `copy metadataLibrary`() {
fun `copy metadataBinary`() {
/* Setup Artifact content */
val primaryArtifactContent = temporaryFolder.newFolder()
@@ -166,7 +166,7 @@ class CompositeMetadataArtifactTest {
/* Extract and assert sourceSetA */
artifactContent.getSourceSet("sourceSetA").also { sourceSetA ->
val sourceSetAMetadataFile = metadataOutputDirectory.resolve("sourceSetA.klib")
assertNotNull(sourceSetA.metadataLibrary).copyTo(sourceSetAMetadataFile)
assertNotNull(sourceSetA.metadataBinary).copyTo(sourceSetAMetadataFile)
assertTrue(sourceSetAMetadataFile.isFile, "Expected sourceSetAMetadataFile.isFile")
assertEquals(
KLIB.archiveExtension, sourceSetAMetadataFile.extension,
@@ -182,7 +182,7 @@ class CompositeMetadataArtifactTest {
/* Extract and assert sourceSetB */
artifactContent.getSourceSet("sourceSetB").also { sourceSetB ->
val sourceSetBMetadataFile = metadataOutputDirectory.resolve("sourceSetB.jar")
assertNotNull(sourceSetB.metadataLibrary).copyTo(sourceSetBMetadataFile)
assertNotNull(sourceSetB.metadataBinary).copyTo(sourceSetBMetadataFile)
assertTrue(sourceSetBMetadataFile.isFile, "Expected sourceSetBMetadataFile.isFile")
assertEquals(
METADATA.archiveExtension, sourceSetBMetadataFile.extension,
@@ -198,7 +198,7 @@ class CompositeMetadataArtifactTest {
}
@Test
fun `copy cinteropMetadataLibraries`() {
fun `copy cinteropMetadataBinaries`() {
/* Setup Artifact content */
val primaryArtifactContent = temporaryFolder.newFolder()
@@ -239,7 +239,7 @@ class CompositeMetadataArtifactTest {
/* Assertions on sourceSetA */
artifactContent.getSourceSet("sourceSetA").also { sourceSetA ->
val sourceSetAOutputDirectory = temporaryFolder.newFolder()
val sourceSetAInteropMetadataFiles = sourceSetA.cinteropMetadataLibraries.map { cinteropLibrary ->
val sourceSetAInteropMetadataFiles = sourceSetA.cinteropMetadataBinaries.map { cinteropLibrary ->
sourceSetAOutputDirectory.resolve("${cinteropLibrary.cinteropLibraryName}.klib").also { file ->
cinteropLibrary.copyTo(file)
}
@@ -272,7 +272,7 @@ class CompositeMetadataArtifactTest {
/* Assertions on sourceSetB */
artifactContent.getSourceSet("sourceSetB").also { sourceSetB ->
val sourceSetBOutputDirectory = temporaryFolder.newFolder()
val sourceSetBInteropMetadataFiles = sourceSetB.cinteropMetadataLibraries.map { cinteropLibrary ->
val sourceSetBInteropMetadataFiles = sourceSetB.cinteropMetadataBinaries.map { cinteropLibrary ->
sourceSetBOutputDirectory.resolve("${cinteropLibrary.cinteropLibraryName}.klib").also { file ->
cinteropLibrary.copyTo(file)
}