From 903fe2d30e044b98e6f59f14c33105baef2e0df3 Mon Sep 17 00:00:00 2001 From: AJ Alt Date: Wed, 22 May 2024 17:50:12 +0000 Subject: [PATCH] Update Kotlin to 2.0.0 (#519) Since Clikt uses a lot on lambdas, compiling with `invokedynamic` reduces the jvm jar size by ~20% --- .gitignore | 1 + CHANGELOG.md | 1 + .../github/ajalt/clikt/core/ContextTest.kt | 1 - clikt/api/clikt.api | 4 ++-- clikt/build.gradle.kts | 4 ++-- .../com/github/ajalt/clikt/core/Context.kt | 1 - .../ajalt/clikt/parsers/CommandLineParser.kt | 5 +--- .../github/ajalt/clikt/parsers/Invocation.kt | 21 +++++++--------- docs/advanced.md | 24 ++++++++++--------- gradle/libs.versions.toml | 4 ++-- 10 files changed, 31 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 0eedd0907..674451266 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ docs/api/ docs/changelog.md docs/index.md kotlin-js-store/ +.kotlin/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 7170c5a36..56d3cb70a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ - **Breaking Change:** `CliktCommand.main` and `CliktCommand.parse` are now extension functions rather than methods. - **Breaking Change:** `Context.obj` and `Context.terminal`, and `OptionTransformContext.terminal` are now extension functions rather than properties. - **Breaking Change:** The `RenderedSection` and `DefinitionRow` classes have moved to `AbstractHelpFormatter`. +- Updated Kotlin to 2.0.0 ### Fixed - Fixed excess arguments not being reported when `allowMultipleSubcommands=true` and a subcommand has excess arguments followed by another subcommand. diff --git a/clikt-mordant/src/commonTest/kotlin/com/github/ajalt/clikt/core/ContextTest.kt b/clikt-mordant/src/commonTest/kotlin/com/github/ajalt/clikt/core/ContextTest.kt index 59368c798..7825cbff5 100644 --- a/clikt-mordant/src/commonTest/kotlin/com/github/ajalt/clikt/core/ContextTest.kt +++ b/clikt-mordant/src/commonTest/kotlin/com/github/ajalt/clikt/core/ContextTest.kt @@ -124,7 +124,6 @@ class ContextTest { } @Test - @OptIn(ExperimentalStdlibApi::class) @JsName("register_closeable_multiple_subcommands") fun `register closeable multiple subcommands`() { var parentCount = 0 diff --git a/clikt/api/clikt.api b/clikt/api/clikt.api index f826b8665..729d1ae59 100644 --- a/clikt/api/clikt.api +++ b/clikt/api/clikt.api @@ -1333,8 +1333,8 @@ public final class com/github/ajalt/clikt/parsers/CommandLineParser { public static synthetic fun tokenize$default (Lcom/github/ajalt/clikt/parsers/CommandLineParser;Ljava/lang/String;Ljava/lang/String;Lcom/github/ajalt/clikt/output/Localization;ILjava/lang/Object;)Ljava/util/List; } -public final class com/github/ajalt/clikt/parsers/FlatInvocations : kotlin/sequences/Sequence { - public final fun close ()V +public final class com/github/ajalt/clikt/parsers/FlatInvocations : java/lang/AutoCloseable, kotlin/sequences/Sequence { + public fun close ()V public fun iterator ()Ljava/util/Iterator; } diff --git a/clikt/build.gradle.kts b/clikt/build.gradle.kts index e99848ab2..fc93f62bd 100644 --- a/clikt/build.gradle.kts +++ b/clikt/build.gradle.kts @@ -46,8 +46,8 @@ kotlin { // https://youtrack.jetbrains.com/issue/KT-63014 // https://github.com/Kotlin/kotlin-wasm-examples/blob/1b007347bf9f8a1ec3d420d30de1815768d5df02/nodejs-example/build.gradle.kts#L22 rootProject.the().apply { - nodeVersion = "22.0.0-nightly202404032241e8c5b3" - nodeDownloadBaseUrl = "https://nodejs.org/download/nightly" + version = "22.0.0-nightly202404032241e8c5b3" + downloadBaseUrl = "https://nodejs.org/download/nightly" } rootProject.tasks.withType().configureEach { diff --git a/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/core/Context.kt b/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/core/Context.kt index 22ac53d57..2d2915545 100644 --- a/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/core/Context.kt +++ b/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/core/Context.kt @@ -427,7 +427,6 @@ class Context private constructor( * @return the closeable that was registered * @see Context.callOnClose */ -@ExperimentalStdlibApi fun Context.registerCloseable(closeable: T): T { callOnClose { closeable.close() } return closeable diff --git a/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/parsers/CommandLineParser.kt b/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/parsers/CommandLineParser.kt index e59536803..0445a95e5 100644 --- a/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/parsers/CommandLineParser.kt +++ b/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/parsers/CommandLineParser.kt @@ -87,13 +87,10 @@ object CommandLineParser { rootInvocation: CommandInvocation, runCommand: (T) -> Unit, ) { - val invocations = rootInvocation.flatten() - try { + rootInvocation.flatten().use { invocations -> for (invocation in invocations) { runCommand(invocation.command) } - } finally { - invocations.close() } } diff --git a/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/parsers/Invocation.kt b/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/parsers/Invocation.kt index b55aabcd3..b9c35f354 100644 --- a/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/parsers/Invocation.kt +++ b/clikt/src/commonMain/kotlin/com/github/ajalt/clikt/parsers/Invocation.kt @@ -87,27 +87,24 @@ class CommandLineParseResult>( * ### Example * * ``` - * val invocations = rootInvocation.flatten() - * try { - * for (inv in invocations) { - * run(inv.command) - * } - * } finally { - * invocations.close() + * rootInvocation.flatten().use { invocations -> + * for (invocation in invocations) { + * runCommand(invocation.command) + * } * } * ``` * - * @param finalize If true (the default), finalize all commands as they are emitted in the sequence. If false, you - * must call [CommandLineParser.finalize] on each invocation yourself before running the command. + * @param finalize If true (the default), finalize all commands as they are emitted in the sequence. + * If false, you must call [CommandLineParser.finalize] on each invocation yourself before running + * the command. */ fun > CommandInvocation.flatten(finalize: Boolean = true): FlatInvocations { return FlatInvocations(this, finalize) } -// TODO: this should be an AutoClosable once that interface is stable class FlatInvocations> internal constructor( root: CommandInvocation, private val finalize: Boolean, -) : Sequence> { +) : Sequence>, AutoCloseable { private val closables = mutableListOf() private val seq = sequence { suspend fun SequenceScope>.yieldSubs(inv: CommandInvocation) { @@ -126,7 +123,7 @@ class FlatInvocations> internal constructor( /** * [Close][Context.close] all open contexts of invoked commands. */ - fun close() { + override fun close() { closables.forEach { it.close() } } } diff --git a/docs/advanced.md b/docs/advanced.md index adcecb60c..4a0b85bb2 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -489,7 +489,7 @@ soon as one of them returns a non-zero status code, you could implement it like abstract class StatusCliktCommand : BaseCliktCommand() { abstract fun run(): Int } - + class ParentCommand : StatusCliktCommand() { override val allowMultipleSubcommands: Boolean = true override fun run(): Int { @@ -497,37 +497,39 @@ soon as one of them returns a non-zero status code, you could implement it like return 0 } } - + class SuccessCommand : StatusCliktCommand() { override fun run(): Int { echo("Success") return 0 } } - + class FailureCommand : StatusCliktCommand() { override fun run(): Int { echo("Failure") return 1001 } } - + fun StatusCliktCommand.parse(argv: Array): Int { val parseResult = CommandLineParser.parse(this, argv.asList()) - for (invocation in parseResult.invocation.flatten()) { - val status = invocation.command.run() - if (status != 0) { - return status + parseResult.invocation.flatten().use { invocations -> + for (invocation in invocations) { + val status = invocation.command.run() + if (status != 0) { + return status + } } } return 0 } - + fun StatusCliktCommand.main(argv: Array) { val status = CommandLineParser.mainReturningValue(this) { parse(argv) } - CliktUtil.exitProcess(status) + exitProcess(status) } - + fun main(argv: Array) { ParentCommand().subcommands(SuccessCommand(), FailureCommand()).main(argv) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 36b771c65..6e2a3dd84 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -kotlin = "1.9.23" -coroutines = "1.8.0" +kotlin = "2.0.0" +coroutines = "1.8.1" [libraries] mordant = "com.github.ajalt.mordant:mordant:2.6.0"