Skip to content

Commit daebfc1

Browse files
authored
KlibDump API imporovements (#253)
- returning the target object (file or appendable) from saveTo - merge and KlibDump.from a char sequence - new "replace" method as a shortcut for remove + merge
1 parent 05741e7 commit daebfc1

File tree

3 files changed

+179
-15
lines changed

3 files changed

+179
-15
lines changed

api/binary-compatibility-validator.api

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,21 @@ public final class kotlinx/validation/api/klib/KlibDump {
141141
public final fun copy ()Lkotlinx/validation/api/klib/KlibDump;
142142
public final fun getTargets ()Ljava/util/Set;
143143
public final fun merge (Ljava/io/File;Ljava/lang/String;)V
144+
public final fun merge (Ljava/lang/CharSequence;Ljava/lang/String;)V
144145
public final fun merge (Lkotlinx/validation/api/klib/KlibDump;)V
145146
public static synthetic fun merge$default (Lkotlinx/validation/api/klib/KlibDump;Ljava/io/File;Ljava/lang/String;ILjava/lang/Object;)V
147+
public static synthetic fun merge$default (Lkotlinx/validation/api/klib/KlibDump;Ljava/lang/CharSequence;Ljava/lang/String;ILjava/lang/Object;)V
146148
public final fun remove (Ljava/lang/Iterable;)V
149+
public final fun replace (Lkotlinx/validation/api/klib/KlibDump;)V
147150
public final fun retain (Ljava/lang/Iterable;)V
148-
public final fun saveTo (Ljava/lang/Appendable;)V
151+
public final fun saveTo (Ljava/lang/Appendable;)Ljava/lang/Appendable;
149152
}
150153

151154
public final class kotlinx/validation/api/klib/KlibDump$Companion {
152155
public final fun from (Ljava/io/File;Ljava/lang/String;)Lkotlinx/validation/api/klib/KlibDump;
156+
public final fun from (Ljava/lang/CharSequence;Ljava/lang/String;)Lkotlinx/validation/api/klib/KlibDump;
153157
public static synthetic fun from$default (Lkotlinx/validation/api/klib/KlibDump$Companion;Ljava/io/File;Ljava/lang/String;ILjava/lang/Object;)Lkotlinx/validation/api/klib/KlibDump;
158+
public static synthetic fun from$default (Lkotlinx/validation/api/klib/KlibDump$Companion;Ljava/lang/CharSequence;Ljava/lang/String;ILjava/lang/Object;)Lkotlinx/validation/api/klib/KlibDump;
154159
public final fun fromKlib (Ljava/io/File;Ljava/lang/String;Lkotlinx/validation/api/klib/KlibDumpFilters;)Lkotlinx/validation/api/klib/KlibDump;
155160
public static synthetic fun fromKlib$default (Lkotlinx/validation/api/klib/KlibDump$Companion;Ljava/io/File;Ljava/lang/String;Lkotlinx/validation/api/klib/KlibDumpFilters;ILjava/lang/Object;)Lkotlinx/validation/api/klib/KlibDump;
156161
}
@@ -186,7 +191,7 @@ public final class kotlinx/validation/api/klib/KlibDumpKt {
186191
public static synthetic fun inferAbi$default (Lkotlinx/validation/api/klib/KlibTarget;Ljava/lang/Iterable;Lkotlinx/validation/api/klib/KlibDump;ILjava/lang/Object;)Lkotlinx/validation/api/klib/KlibDump;
187192
public static final fun mergeFromKlib (Lkotlinx/validation/api/klib/KlibDump;Ljava/io/File;Ljava/lang/String;Lkotlinx/validation/api/klib/KlibDumpFilters;)V
188193
public static synthetic fun mergeFromKlib$default (Lkotlinx/validation/api/klib/KlibDump;Ljava/io/File;Ljava/lang/String;Lkotlinx/validation/api/klib/KlibDumpFilters;ILjava/lang/Object;)V
189-
public static final fun saveTo (Lkotlinx/validation/api/klib/KlibDump;Ljava/io/File;)V
194+
public static final fun saveTo (Lkotlinx/validation/api/klib/KlibDump;Ljava/io/File;)Ljava/io/File;
190195
}
191196

192197
public final class kotlinx/validation/api/klib/KlibSignatureVersion : java/io/Serializable {

src/main/kotlin/api/klib/KlibDump.kt

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package kotlinx.validation.api.klib
77

88
import kotlinx.validation.ExperimentalBCVApi
9-
import org.jetbrains.kotlin.ir.backend.js.MainModule
109
import java.io.File
1110
import java.io.FileNotFoundException
1211

@@ -38,8 +37,7 @@ import java.io.FileNotFoundException
3837
* ```kotlin
3938
* val mergedDump = KlibDump.from(File("/path/to/merged.klib.api"))
4039
* val newTargetDump = KlibDump.fromKlib(File("/path/to/library-linuxX64.klib"))
41-
* mergedDump.remove(newTargetDump.targets)
42-
* mergedDump.merge(newTargetDump)
40+
* mergedDump.replace(newTargetDump)
4341
* mergedDump.saveTo(File("/path/to/merged.klib.api"))
4442
* ```
4543
*/
@@ -72,6 +70,7 @@ public class KlibDump {
7270
* @throws IllegalArgumentException if [dumpFile] contains multiple targets
7371
* and [configurableTargetName] is not null.
7472
* @throws IllegalArgumentException if [dumpFile] is not a file.
73+
* @throws IllegalArgumentException if [dumpFile] is empty.
7574
* @throws FileNotFoundException if [dumpFile] does not exist.
7675
*
7776
* @sample samples.KlibDumpSamples.mergeDumps
@@ -82,6 +81,29 @@ public class KlibDump {
8281
merger.merge(dumpFile, configurableTargetName)
8382
}
8483

84+
/**
85+
* Reads a textual KLib dump from the [dump] char sequence and merges it into this dump.
86+
*
87+
* If a dump contains only a single target, it's possible to specify a custom configurable target name.
88+
* Please refer to [KlibTarget.configurableName] for more details on the meaning of that name.
89+
*
90+
* By default, [configurableTargetName] is null and information about a target will be taken directly from
91+
* the loaded dump.
92+
*
93+
* It's an error to specify non-null [configurableTargetName] for a dump containing multiple targets.
94+
* It's also an error to merge dumps having some targets in common.
95+
*
96+
* @throws IllegalArgumentException if this dump and the provided [dump] shares same targets.
97+
* @throws IllegalArgumentException if the provided [dump] contains multiple targets
98+
* and [configurableTargetName] is not null.
99+
* @throws IllegalArgumentException if the provided [dump] is empty.
100+
*
101+
* @sample samples.KlibDumpSamples.updateMergedDump
102+
*/
103+
public fun merge(dump: CharSequence, configurableTargetName: String? = null) {
104+
merger.merge(dump.lineSequence().iterator(), configurableTargetName)
105+
}
106+
85107
/**
86108
* Merges [other] dump with this one.
87109
*
@@ -101,6 +123,19 @@ public class KlibDump {
101123
merger.merge(other.merger)
102124
}
103125

126+
/**
127+
* Removes the targets from this dump that are contained in the [other] targets set and all their declarations.
128+
* Then merges the [other] dump with this one.
129+
*
130+
* The operation does not modify [other].
131+
*
132+
* @sample samples.KlibDumpSamples.updateMergedDump
133+
*/
134+
public fun replace(other: KlibDump) {
135+
remove(other.targets)
136+
merge(other)
137+
}
138+
104139
/**
105140
* Removes all declarations that do not belong to specified targets and removes these targets from the dump.
106141
*
@@ -134,10 +169,13 @@ public class KlibDump {
134169
/**
135170
* Serializes the dump and writes it to [to].
136171
*
172+
* @return the target [to] where the dump was written.
173+
*
137174
* @sample samples.KlibDumpSamples.mergeDumps
138175
*/
139-
public fun saveTo(to: Appendable) {
176+
public fun <A : Appendable> saveTo(to: A): A {
140177
merger.dump(to)
178+
return to
141179
}
142180

143181
public companion object {
@@ -166,6 +204,28 @@ public class KlibDump {
166204
return KlibDump().apply { merge(dumpFile, configurableTargetName) }
167205
}
168206

207+
/**
208+
* Reads a dump from a textual form.
209+
*
210+
* If a dump contains only a single target, it's possible to specify a custom configurable target name.
211+
* Please refer to [KlibTarget.configurableName] for more details on the meaning of that name.
212+
*
213+
* By default, [configurableTargetName] is null and information about a target will be taken directly from
214+
* the loaded dump.
215+
*
216+
* It's an error to specify non-null [configurableTargetName] for a dump containing multiple targets.
217+
*
218+
* @throws IllegalArgumentException if this dump and the provided [dump] shares same targets.
219+
* @throws IllegalArgumentException if the provided [dump] contains multiple targets
220+
* and [configurableTargetName] is not null.
221+
* @throws IllegalArgumentException if the provided [dump] is empty.
222+
*
223+
* @sample samples.KlibDumpSamples.updateMergedDump
224+
*/
225+
public fun from(dump: CharSequence, configurableTargetName: String? = null): KlibDump {
226+
return KlibDump().apply { merge(dump, configurableTargetName) }
227+
}
228+
169229
/**
170230
* Dumps a public ABI of a klib represented by [klibFile] using [filters]
171231
* and returns a [KlibDump] representing it.
@@ -278,6 +338,8 @@ public fun KlibDump.mergeFromKlib(
278338

279339
/**
280340
* Serializes the dump and writes it to [file].
341+
*
342+
* @return the target [file].
281343
*/
282344
@ExperimentalBCVApi
283-
public fun KlibDump.saveTo(file: File): Unit = file.bufferedWriter().use { saveTo(it) }
345+
public fun KlibDump.saveTo(file: File): File = file.apply { bufferedWriter().use { saveTo(it) } }

src/test/kotlin/samples/KlibDumpSamples.kt

Lines changed: 105 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class KlibDumpSamples {
2020
@Rule
2121
var tempFolder = TemporaryFolder()
2222

23-
fun createDumpWithContent(content: String): File {
23+
fun createDumpFileWithContent(content: String): File {
2424
val file = tempFolder.newFile()
2525
file.writer().use {
2626
it.write(content)
@@ -31,7 +31,7 @@ class KlibDumpSamples {
3131
@OptIn(ExperimentalBCVApi::class)
3232
@Test
3333
fun mergeDumps() {
34-
val linuxX64Dump = createDumpWithContent("""
34+
val linuxX64Dump = createDumpFileWithContent("""
3535
// Rendering settings:
3636
// - Signature version: 2
3737
// - Show manifest properties: false
@@ -51,7 +51,7 @@ class KlibDumpSamples {
5151
final fun org.example/ShardedClass(kotlin/Int, kotlin/Float, kotlin/Long): org.example/ShardedClass // org.example/ShardedClass|ShardedClass(kotlin.Int;kotlin.Float;kotlin.Long){}[0]
5252
""".trimIndent())
5353

54-
val linuxArm64Dump = createDumpWithContent("""
54+
val linuxArm64Dump = createDumpFileWithContent("""
5555
// Rendering settings:
5656
// - Signature version: 2
5757
// - Show manifest properties: false
@@ -103,7 +103,7 @@ class KlibDumpSamples {
103103
@OptIn(ExperimentalBCVApi::class)
104104
@Test
105105
fun mergeDumpObjects() {
106-
val linuxX64Dump = createDumpWithContent("""
106+
val linuxX64Dump = createDumpFileWithContent("""
107107
// Rendering settings:
108108
// - Signature version: 2
109109
// - Show manifest properties: false
@@ -123,7 +123,7 @@ class KlibDumpSamples {
123123
final fun org.example/ShardedClass(kotlin/Int, kotlin/Float, kotlin/Long): org.example/ShardedClass // org.example/ShardedClass|ShardedClass(kotlin.Int;kotlin.Float;kotlin.Long){}[0]
124124
""".trimIndent())
125125

126-
val linuxArm64Dump = createDumpWithContent("""
126+
val linuxArm64Dump = createDumpFileWithContent("""
127127
// Rendering settings:
128128
// - Signature version: 2
129129
// - Show manifest properties: false
@@ -193,11 +193,108 @@ class KlibDumpSamples {
193193
""".trimIndent(), filteredDumpContent)
194194
}
195195

196+
@OptIn(ExperimentalBCVApi::class)
197+
@Test
198+
fun updateMergedDump() {
199+
val linuxX64Dump = """
200+
// Rendering settings:
201+
// - Signature version: 2
202+
// - Show manifest properties: false
203+
// - Show declarations: true
204+
205+
// Library unique name: <org.example:bcv-klib-test>
206+
// Platform: NATIVE
207+
// Native targets: linux_x64
208+
// Compiler version: 1.9.22
209+
// ABI version: 1.8.0
210+
final class org.example/ShardedClass { // org.example/ShardedClass|null[0]
211+
final val value // org.example/ShardedClass.value|{}value[0]
212+
final fun <get-value>(): kotlin/Int // org.example/ShardedClass.value.<get-value>|<get-value>(){}[0]
213+
constructor <init>(kotlin/Int) // org.example/ShardedClass.<init>|<init>(kotlin.Int){}[0]
214+
final fun add(kotlin/Int): kotlin/Int // org.example/ShardedClass.add|add(kotlin.Int){}[0]
215+
}
216+
final fun org.example/ShardedClass(kotlin/Int, kotlin/Float, kotlin/Long): org.example/ShardedClass // org.example/ShardedClass|ShardedClass(kotlin.Int;kotlin.Float;kotlin.Long){}[0]
217+
""".trimIndent()
218+
219+
val linuxArm64Dump = """
220+
// Rendering settings:
221+
// - Signature version: 2
222+
// - Show manifest properties: false
223+
// - Show declarations: true
224+
225+
// Library unique name: <org.example:bcv-klib-test>
226+
// Platform: NATIVE
227+
// Native targets: linux_arm64
228+
// Compiler version: 1.9.22
229+
// ABI version: 1.8.0
230+
final class org.example/ShardedClass { // org.example/ShardedClass|null[0]
231+
final val value // org.example/ShardedClass.value|{}value[0]
232+
final fun <get-value>(): kotlin/Int // org.example/ShardedClass.value.<get-value>|<get-value>(){}[0]
233+
constructor <init>(kotlin/Int) // org.example/ShardedClass.<init>|<init>(kotlin.Int){}[0]
234+
final fun add(kotlin/Int): kotlin/Int // org.example/ShardedClass.add|add(kotlin.Int){}[0]
235+
}
236+
""".trimIndent()
237+
238+
val mergedDump = KlibDump()
239+
mergedDump.merge(KlibDump.from(linuxArm64Dump))
240+
mergedDump.merge(KlibDump.from(linuxX64Dump, configurableTargetName = "linuxX86_64"))
241+
242+
val newLinuxX64Dump = """
243+
// Rendering settings:
244+
// - Signature version: 2
245+
// - Show manifest properties: false
246+
// - Show declarations: true
247+
248+
// Library unique name: <org.example:bcv-klib-test>
249+
// Platform: NATIVE
250+
// Native targets: linux_x64
251+
// Compiler version: 1.9.22
252+
// ABI version: 1.8.0
253+
final class org.example/ShardedClass { // org.example/ShardedClass|null[0]
254+
final val value // org.example/ShardedClass.value|{}value[0]
255+
final fun <get-value>(): kotlin/Int // org.example/ShardedClass.value.<get-value>|<get-value>(){}[0]
256+
constructor <init>(kotlin/Int) // org.example/ShardedClass.<init>|<init>(kotlin.Int){}[0]
257+
final fun store(kotlin/Int): kotlin/Int // org.example/ShardedClass.store|store(kotlin.Long){}[0]
258+
}
259+
final fun org.example/ShardedClass(kotlin/Int, kotlin/Float, kotlin/Long): org.example/ShardedClass // org.example/ShardedClass|ShardedClass(kotlin.Int;kotlin.Float;kotlin.Long){}[0]
260+
""".trimIndent()
261+
262+
mergedDump.replace(KlibDump.from(newLinuxX64Dump, configurableTargetName = "linuxX86_64"))
263+
264+
val mergedDumpContent = mergedDump.saveTo(StringBuilder()).toString()
265+
assertEquals("""
266+
// Klib ABI Dump
267+
// Targets: [linuxArm64, linuxX64.linuxX86_64]
268+
// Rendering settings:
269+
// - Signature version: 2
270+
// - Show manifest properties: false
271+
// - Show declarations: true
272+
273+
// Library unique name: <org.example:bcv-klib-test>
274+
final class org.example/ShardedClass { // org.example/ShardedClass|null[0]
275+
constructor <init>(kotlin/Int) // org.example/ShardedClass.<init>|<init>(kotlin.Int){}[0]
276+
277+
final val value // org.example/ShardedClass.value|{}value[0]
278+
final fun <get-value>(): kotlin/Int // org.example/ShardedClass.value.<get-value>|<get-value>(){}[0]
279+
280+
// Targets: [linuxArm64]
281+
final fun add(kotlin/Int): kotlin/Int // org.example/ShardedClass.add|add(kotlin.Int){}[0]
282+
283+
// Targets: [linuxX64.linuxX86_64]
284+
final fun store(kotlin/Int): kotlin/Int // org.example/ShardedClass.store|store(kotlin.Long){}[0]
285+
}
286+
287+
// Targets: [linuxX64.linuxX86_64]
288+
final fun org.example/ShardedClass(kotlin/Int, kotlin/Float, kotlin/Long): org.example/ShardedClass // org.example/ShardedClass|ShardedClass(kotlin.Int;kotlin.Float;kotlin.Long){}[0]
289+
290+
""".trimIndent(), mergedDumpContent)
291+
}
292+
196293
@OptIn(ExperimentalBCVApi::class)
197294
@Test
198295
fun extractTargets() {
199296
// Oh no, we're running on Windows and Apple targets are unsupported, let's filter it out!
200-
val mergedDump = createDumpWithContent("""
297+
val mergedDump = createDumpFileWithContent("""
201298
// Klib ABI Dump
202299
// Targets: [iosArm64, iosSimulatorArm64, iosX64, linuxArm64, linuxX64]
203300
// Rendering settings:
@@ -243,7 +340,7 @@ class KlibDumpSamples {
243340
// We want to get a dump for iosArm64, but our host compiler doesn't support it.
244341
val unsupportedTarget = KlibTarget.parse("iosArm64")
245342
// Thankfully, we have an old merged dump ...
246-
val oldMergedDump = createDumpWithContent("""
343+
val oldMergedDump = createDumpFileWithContent("""
247344
// Klib ABI Dump
248345
// Targets: [iosArm64, linuxArm64]
249346
// Rendering settings:
@@ -260,7 +357,7 @@ class KlibDumpSamples {
260357
""".trimIndent())
261358

262359
// ... and a new dump for linuxArm64
263-
val linuxDump = createDumpWithContent("""
360+
val linuxDump = createDumpFileWithContent("""
264361
// Klib ABI Dump
265362
// Targets: [linuxArm64]
266363
// Rendering settings:

0 commit comments

Comments
 (0)