KLIB API: Write metadata through `KlibMetadataWriterImpl` (in tests) The new `KlibMetadataWriterImpl` class is the replacement for the obsolete KLIB writing API. In this commit, `KlibMetadataWriterImpl` is integrated into the KLIB mock DSL. ^KT-81411
diff --git a/compiler/util-klib/src/org/jetbrains/kotlin/library/components/KlibMetadataComponent.kt b/compiler/util-klib/src/org/jetbrains/kotlin/library/components/KlibMetadataComponent.kt index d75a95c..082e098 100644 --- a/compiler/util-klib/src/org/jetbrains/kotlin/library/components/KlibMetadataComponent.kt +++ b/compiler/util-klib/src/org/jetbrains/kotlin/library/components/KlibMetadataComponent.kt
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.metadata.ProtoBuf /** - * This component provides access to Klib metadata. + * This component provides read access to Klib metadata. */ interface KlibMetadataComponent : KlibComponent { /** The metadata header in the raw form (bytes, yet to be deserialized to [KlibMetadataProtoBuf.Header]). */ @@ -37,6 +37,8 @@ get() = getComponent(KlibMetadataComponent.ID) class KlibMetadataComponentLayout(root: KlibFile) : KlibComponent.Layout(root) { + constructor(root: String) : this(KlibFile(root)) + /** The metadata directory. */ val metadataDir: KlibFile get() = root.child(KLIB_DEFAULT_COMPONENT_NAME).child(KLIB_METADATA_FOLDER_NAME)
diff --git a/compiler/util-klib/src/org/jetbrains/kotlin/library/impl/KlibMetadataWriterImpl.kt b/compiler/util-klib/src/org/jetbrains/kotlin/library/impl/KlibMetadataWriterImpl.kt new file mode 100644 index 0000000..dca9da3 --- /dev/null +++ b/compiler/util-klib/src/org/jetbrains/kotlin/library/impl/KlibMetadataWriterImpl.kt
@@ -0,0 +1,41 @@ +/* + * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.library.impl + +import org.jetbrains.kotlin.library.SerializedMetadata +import org.jetbrains.kotlin.library.components.KlibMetadataComponent +import org.jetbrains.kotlin.library.components.KlibMetadataComponentLayout +import org.jetbrains.kotlin.konan.file.File as KlibFile + +/** + * On the contrary to [KlibMetadataComponent], which provides read access to metadata, + * [KlibMetadataWriterImpl] provides allows writing the metadata to the file system. + */ +internal class KlibMetadataWriterImpl(private val layout: KlibMetadataComponentLayout) { + fun writeMetadata(serializedMetadata: SerializedMetadata) { + layout.metadataDir.mkdirs() + + layout.moduleHeaderFile.writeBytes(serializedMetadata.module) + + serializedMetadata.fragmentNames.forEachIndexed { index, packageFqName -> + val packageFragmentDir: KlibFile = layout.getPackageFragmentsDir(packageFqName) + packageFragmentDir.mkdirs() + + val shortPackageName: String = packageFqName.substringAfterLast(".") + val packageFragmentParts: List<ByteArray> = serializedMetadata.fragments[index] + + val padding: Int = packageFragmentParts.size.toString().length + fun withPadding(packageFragmentPartIndex: Int) = String.format("%0${padding}d", packageFragmentPartIndex) + + packageFragmentParts.forEachIndexed { packageFragmentPartIndex, packageFragmentPart -> + layout.getPackageFragmentFile( + packageFqName = packageFqName, + partName = "${withPadding(packageFragmentPartIndex)}_$shortPackageName" + ).writeBytes(packageFragmentPart) + } + } + } +}
diff --git a/compiler/util-klib/testFixtures/org/jetbrains/kotlin/library/KlibMockDSL.kt b/compiler/util-klib/testFixtures/org/jetbrains/kotlin/library/KlibMockDSL.kt index 8620b63..97c4833 100644 --- a/compiler/util-klib/testFixtures/org/jetbrains/kotlin/library/KlibMockDSL.kt +++ b/compiler/util-klib/testFixtures/org/jetbrains/kotlin/library/KlibMockDSL.kt
@@ -15,14 +15,12 @@ import org.jetbrains.kotlin.library.IrKotlinLibraryLayout.Companion.IR_SIGNATURES_FILE_NAME import org.jetbrains.kotlin.library.IrKotlinLibraryLayout.Companion.IR_STRINGS_FILE_NAME import org.jetbrains.kotlin.library.IrKotlinLibraryLayout.Companion.IR_TYPES_FILE_NAME +import org.jetbrains.kotlin.library.components.KlibMetadataComponentLayout import org.jetbrains.kotlin.library.components.KlibMetadataConstants.KLIB_METADATA_FOLDER_NAME -import org.jetbrains.kotlin.library.components.KlibMetadataConstants.KLIB_MODULE_METADATA_FILE_NAME -import org.jetbrains.kotlin.library.components.KlibMetadataConstants.KLIB_NONROOT_PACKAGE_FRAGMENT_FOLDER_PREFIX -import org.jetbrains.kotlin.library.components.KlibMetadataConstants.KLIB_ROOT_PACKAGE_FRAGMENT_FOLDER_NAME -import org.jetbrains.kotlin.library.components.KlibMetadataConstants.KLIB_METADATA_FILE_EXTENSION import org.jetbrains.kotlin.library.impl.BuiltInsPlatform import org.jetbrains.kotlin.library.impl.IrArrayWriter import org.jetbrains.kotlin.library.impl.KLIB_DEFAULT_COMPONENT_NAME +import org.jetbrains.kotlin.library.impl.KlibMetadataWriterImpl import java.io.File import kotlin.collections.map import kotlin.random.Random @@ -164,29 +162,10 @@ fun KlibMockDSL.metadata(init: KlibMockDSL.() -> Unit = {}): Unit = dir(KLIB_METADATA_FOLDER_NAME, init) -// TODO (KT-81411): rewrite it on the new metadata component layout -fun KlibMockDSL.metadata(metadata: SerializedMetadata) = metadata { - file(KLIB_MODULE_METADATA_FILE_NAME, metadata.module) - - metadata.fragmentNames.forEachIndexed { index, packageName -> - val fragmentDirName = if (packageName == "") - KLIB_ROOT_PACKAGE_FRAGMENT_FOLDER_NAME - else - "$KLIB_NONROOT_PACKAGE_FRAGMENT_FOLDER_PREFIX$packageName" - val shortPackageName = packageName.substringAfterLast(".") - - dir(fragmentDirName) { - val fragmentParts = metadata.fragments[index] - - val padding = fragmentParts.size.toString().length - fun withPadding(fragmentPartIndex: Int) = String.format("%0${padding}d", fragmentPartIndex) - - fragmentParts.forEachIndexed { fragmentPartIndex, fragmentPart -> - val fragmentPartFileName = "${withPadding(fragmentPartIndex)}_$shortPackageName.$KLIB_METADATA_FILE_EXTENSION" - file(fragmentPartFileName, fragmentPart) - } - } - } +fun KlibMockDSL.metadata(metadata: SerializedMetadata) { + val layout = KlibMetadataComponentLayout(rootDir.path) + val writer = KlibMetadataWriterImpl(layout) + writer.writeMetadata(metadata) } fun KlibMockDSL.ir(init: KlibMockDSL.() -> Unit = {}): Unit = dir(KLIB_IR_FOLDER_NAME, init)