From e5d35f7d1a99197273bc71867fa8697253b196d0 Mon Sep 17 00:00:00 2001 From: Anton Lakotka Date: Fri, 2 Jun 2023 18:55:25 +0200 Subject: [PATCH] [Gradle] deprecate android and introduce androidTarget preset Android preset needs to be removed in favor of Android Pluggable Target Changes were originally introduced by commit: becf50ee0f797c7996fe6becddeb405badc7b7fc but then, unfortunately, reverted due to binary compatibility issues ^KT-59049 Verification Pending ^KT-57903 Verification Pending --- .../gradle/dsl/mppPresetFunctionsCodegen.kt | 61 +++++++++++++++---- .../generators/gradle/dsl/presetEntries.kt | 47 ++++++++++++-- .../dsl/KotlinMultiplatformExtension.kt | 18 ------ ...otlinTargetContainerWithPresetFunctions.kt | 47 +++++++++++--- 4 files changed, 131 insertions(+), 42 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-dsl-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/dsl/mppPresetFunctionsCodegen.kt b/libraries/tools/kotlin-gradle-plugin-dsl-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/dsl/mppPresetFunctionsCodegen.kt index 5f261548ab1..e1916f5a3c5 100644 --- a/libraries/tools/kotlin-gradle-plugin-dsl-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/dsl/mppPresetFunctionsCodegen.kt +++ b/libraries/tools/kotlin-gradle-plugin-dsl-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/dsl/mppPresetFunctionsCodegen.kt @@ -20,9 +20,7 @@ private val presetsProperty = KotlinTargetsContainerWithPresets::presets.name private fun generateKotlinTargetContainerWithPresetFunctionsInterface() { // Generate KotlinMultiplatformExtension subclass with member functions for the presets: val functions = allPresetEntries.map { kotlinPreset -> - // magic indent is needed to make the result look pretty - val funPrefix = kotlinPreset.deprecation?.let { "\n $it\n @Suppress(\"DEPRECATION_ERROR\")\n " } ?: "" - generatePresetFunctions(kotlinPreset, presetsProperty, "configureOrCreate", funPrefix) + generatePresetFunctions(kotlinPreset, presetsProperty, "configureOrCreate") } val parentInterfaceName = @@ -45,10 +43,13 @@ private fun generateKotlinTargetContainerWithPresetFunctionsInterface() { val generatedCodeWarning = "// DO NOT EDIT MANUALLY! Generated by ${object {}.javaClass.enclosingClass.name}" + val extraTopLevelDeclarations = allPresetEntries.flatMap { it.extraTopLevelDeclarations }.joinToString("\n") + val code = listOf( "package ${className.packageName()}", imports, generatedCodeWarning, + extraTopLevelDeclarations, "interface ${className.renderShort()} : ${parentInterfaceName.renderShort()} {", functions.joinToString("\n\n") { it.indented(4) }, "}" @@ -62,23 +63,59 @@ private fun generatePresetFunctions( presetEntry: KotlinPresetEntry, getPresetsExpression: String, configureOrCreateFunctionName: String, - funPrefix: String = "" ): String { + fun deprecated(replaceWithArguments: List? = null): String { + val deprecation = presetEntry.deprecation ?: return "" + + val deprecationAnnotation = if (deprecation.replaceWithOtherPreset != null && replaceWithArguments != null) { + val replaceWith = "ReplaceWith(\"${deprecation.replaceWithOtherPreset}(${replaceWithArguments.joinToString(",")})\")" + "@Deprecated(${deprecation.message}, level = DeprecationLevel.${deprecation.level.name}, replaceWith = $replaceWith)" + } else { + "@Deprecated(${deprecation.message}, level = DeprecationLevel.${deprecation.level.name})" + } + + // magic indent is needed to make the result look pretty + return "\n $deprecationAnnotation\n " + } + + val suppress = if (presetEntry.deprecation != null) { + val suppressDeprecationId = when (presetEntry.deprecation.level) { + DeprecationLevel.WARNING -> "DEPRECATION" + DeprecationLevel.ERROR -> "DEPRECATION_ERROR" + DeprecationLevel.HIDDEN -> "DEPRECATION_HIDDEN" + } + "@Suppress(\"$suppressDeprecationId\")\n " + } else { + "" + } + + val alsoBlockAfterConfiguration = if (presetEntry.alsoBlockAfterConfiguration != null) { + """ + .also { + ${presetEntry.alsoBlockAfterConfiguration.indented(16, skipFirstLine = true)} + } + """.trimIndent().indented(8, skipFirstLine = true) + } else { + "" + } + val presetName = presetEntry.presetName + val entityName = presetEntry.entityName + return """ - ${funPrefix}fun $presetName( - name: String = "$presetName", + ${deprecated()}fun $presetName( + name: String = "$entityName", configure: ${presetEntry.targetType.renderShort()}.() -> Unit = { } ): ${presetEntry.targetType.renderShort()} = $configureOrCreateFunctionName( name, - $getPresetsExpression.getByName("$presetName") as ${presetEntry.presetType.renderShort()}, + $getPresetsExpression.getByName("$entityName") as ${presetEntry.presetType.renderShort()}, configure - ) + )$alsoBlockAfterConfiguration - ${funPrefix}fun $presetName() = $presetName("$presetName") { } - ${funPrefix}fun $presetName(name: String) = $presetName(name) { } - ${funPrefix}fun $presetName(name: String, configure: Action<${presetEntry.targetType.renderShort()}>) = $presetName(name) { configure.execute(this) } - ${funPrefix}fun $presetName(configure: Action<${presetEntry.targetType.renderShort()}>) = $presetName { configure.execute(this) } + ${deprecated(emptyList())}${suppress}fun $presetName() = $presetName("$entityName") { } + ${deprecated(listOf("name"))}${suppress}fun $presetName(name: String) = $presetName(name) { } + ${deprecated()}${suppress}fun $presetName(name: String, configure: Action<${presetEntry.targetType.renderShort()}>) = $presetName(name) { configure.execute(this) } + ${deprecated()}${suppress}fun $presetName(configure: Action<${presetEntry.targetType.renderShort()}>) = $presetName { configure.execute(this) } """.trimIndent() } diff --git a/libraries/tools/kotlin-gradle-plugin-dsl-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/dsl/presetEntries.kt b/libraries/tools/kotlin-gradle-plugin-dsl-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/dsl/presetEntries.kt index 8cb17e2d781..2acd9b6ef39 100644 --- a/libraries/tools/kotlin-gradle-plugin-dsl-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/dsl/presetEntries.kt +++ b/libraries/tools/kotlin-gradle-plugin-dsl-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/dsl/presetEntries.kt @@ -15,8 +15,19 @@ internal class KotlinPresetEntry( val presetName: String, val presetType: TypeName, val targetType: TypeName, - val deprecation: String? = null -) + val deprecation: Deprecation? = null, + val entityName: String = presetName, + // Adds `.also { $alsoBlockAfterConfiguration }` after configureOrCreate(...) + val alsoBlockAfterConfiguration: String? = null, + // Extra declarations will be inserted before functions are generated + val extraTopLevelDeclarations: List = emptyList(), +) { + class Deprecation( + val message: String, + val level: DeprecationLevel, + val replaceWithOtherPreset: String? = null // when set, it will generate ReplaceWith with related argument names + ) +} internal fun KotlinPresetEntry.typeNames(): Set = setOf(presetType, targetType) @@ -42,10 +53,34 @@ internal val jvmPresetEntry = KotlinPresetEntry( typeName("org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget") ) +internal val androidTargetPresetEntry = KotlinPresetEntry( + "androidTarget", + typeName("$MPP_PACKAGE.KotlinAndroidTargetPreset"), + typeName("$MPP_PACKAGE.KotlinAndroidTarget"), + entityName = "android", +) + internal val androidPresetEntry = KotlinPresetEntry( "android", typeName("$MPP_PACKAGE.KotlinAndroidTargetPreset"), - typeName("$MPP_PACKAGE.KotlinAndroidTarget") + typeName("$MPP_PACKAGE.KotlinAndroidTarget"), + deprecation = KotlinPresetEntry.Deprecation( + message = "ANDROID_TARGET_MIGRATION_MESSAGE", + level = DeprecationLevel.WARNING, + replaceWithOtherPreset = "androidTarget" + ), + extraTopLevelDeclarations = listOf( + "private const val ANDROID_TARGET_MIGRATION_MESSAGE" + + " = \"Please use androidTarget() instead. Learn more here: https://kotl.in/android-target-dsl\"" + ), + alsoBlockAfterConfiguration = """ + it.project.logger.warn( + ""${'"'} + w: Please use `androidTarget` function instead of `android` to configure android target inside `kotlin { }` block. + See the details here: https://kotl.in/android-target-dsl + ""${'"'}.trimIndent() + ) + """.trimIndent() ) // Note: modifying these sets should also be reflected in the MPP plugin code, see 'setupDefaultPresets' @@ -75,12 +110,16 @@ internal val nativePresetEntries = HostManager().targets else -> Presets.simple to Targets.base } - val deprecation = "@Deprecated(DEPRECATED_TARGET_MESSAGE, level = DeprecationLevel.ERROR)".takeIf { target in KonanTarget.deprecatedTargets } + val deprecation = KotlinPresetEntry.Deprecation( + message = "DEPRECATED_TARGET_MESSAGE", + level = DeprecationLevel.ERROR + ).takeIf { target in KonanTarget.deprecatedTargets } KotlinPresetEntry(target.presetName, typeName(presetType), typeName(targetType), deprecation) } internal val allPresetEntries = listOf( jvmPresetEntry, + androidTargetPresetEntry, androidPresetEntry ) + nativePresetEntries diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt index 4a44c867e1b..67a10d63084 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt @@ -6,8 +6,6 @@ package org.jetbrains.kotlin.gradle.dsl import org.gradle.api.* -import org.gradle.api.internal.plugins.DslObject -import org.gradle.api.logging.Logger import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseDsl @@ -163,20 +161,4 @@ internal fun KotlinTargetsContainerWithPresets.configureOrCre ) } } -} - -internal fun KotlinTargetsContainerWithPresets.configureOrCreateAndroidTargetAndReportDeprecation( - targetName: String, - configure: KotlinAndroidTarget.() -> Unit, -): KotlinAndroidTarget { - val targetPreset = presets.getByName("android") as KotlinAndroidTargetPreset - val result = configureOrCreate(targetName, targetPreset, configure) - - result.project.logger.warn( - """ - w: Please use `androidTarget` function instead of `android` to configure android target inside `kotlin { }` block. - See the details here: https://kotl.in/android-target-dsl - """.trimIndent() - ) - return result } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinTargetContainerWithPresetFunctions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinTargetContainerWithPresetFunctions.kt index d8a1c7d926c..db209847509 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinTargetContainerWithPresetFunctions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinTargetContainerWithPresetFunctions.kt @@ -16,6 +16,8 @@ import org.jetbrains.kotlin.konan.target.DEPRECATED_TARGET_MESSAGE // DO NOT EDIT MANUALLY! Generated by org.jetbrains.kotlin.generators.gradle.dsl.MppPresetFunctionsCodegenKt +private const val ANDROID_TARGET_MIGRATION_MESSAGE = "Please use androidTarget() instead. Learn more here: https://kotl.in/android-target-dsl" + interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithPresets { fun jvm( @@ -33,7 +35,7 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP fun jvm(name: String, configure: Action) = jvm(name) { configure.execute(this) } fun jvm(configure: Action) = jvm { configure.execute(this) } - fun android( + fun androidTarget( name: String = "android", configure: KotlinAndroidTarget.() -> Unit = { } ): KotlinAndroidTarget = @@ -43,9 +45,45 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP configure ) + fun androidTarget() = androidTarget("android") { } + fun androidTarget(name: String) = androidTarget(name) { } + fun androidTarget(name: String, configure: Action) = androidTarget(name) { configure.execute(this) } + fun androidTarget(configure: Action) = androidTarget { configure.execute(this) } + + + @Deprecated(ANDROID_TARGET_MIGRATION_MESSAGE, level = DeprecationLevel.WARNING) + fun android( + name: String = "android", + configure: KotlinAndroidTarget.() -> Unit = { } + ): KotlinAndroidTarget = + configureOrCreate( + name, + presets.getByName("android") as KotlinAndroidTargetPreset, + configure + ).also { + it.project.logger.warn( + """ + w: Please use `androidTarget` function instead of `android` to configure android target inside `kotlin { }` block. + See the details here: https://kotl.in/android-target-dsl + """.trimIndent() + ) + } + + + @Deprecated(ANDROID_TARGET_MIGRATION_MESSAGE, level = DeprecationLevel.WARNING, replaceWith = ReplaceWith("androidTarget()")) + @Suppress("DEPRECATION") fun android() = android("android") { } + + @Deprecated(ANDROID_TARGET_MIGRATION_MESSAGE, level = DeprecationLevel.WARNING, replaceWith = ReplaceWith("androidTarget(name)")) + @Suppress("DEPRECATION") fun android(name: String) = android(name) { } + + @Deprecated(ANDROID_TARGET_MIGRATION_MESSAGE, level = DeprecationLevel.WARNING) + @Suppress("DEPRECATION") fun android(name: String, configure: Action) = android(name) { configure.execute(this) } + + @Deprecated(ANDROID_TARGET_MIGRATION_MESSAGE, level = DeprecationLevel.WARNING) + @Suppress("DEPRECATION") fun android(configure: Action) = android { configure.execute(this) } fun androidNativeX64( @@ -110,7 +148,6 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP @Deprecated(DEPRECATED_TARGET_MESSAGE, level = DeprecationLevel.ERROR) - @Suppress("DEPRECATION_ERROR") fun iosArm32( name: String = "iosArm32", configure: KotlinNativeTarget.() -> Unit = { } @@ -215,7 +252,6 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP @Deprecated(DEPRECATED_TARGET_MESSAGE, level = DeprecationLevel.ERROR) - @Suppress("DEPRECATION_ERROR") fun watchosX86( name: String = "watchosX86", configure: KotlinNativeTargetWithSimulatorTests.() -> Unit = { } @@ -350,7 +386,6 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP @Deprecated(DEPRECATED_TARGET_MESSAGE, level = DeprecationLevel.ERROR) - @Suppress("DEPRECATION_ERROR") fun mingwX86( name: String = "mingwX86", configure: KotlinNativeTarget.() -> Unit = { } @@ -440,7 +475,6 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP @Deprecated(DEPRECATED_TARGET_MESSAGE, level = DeprecationLevel.ERROR) - @Suppress("DEPRECATION_ERROR") fun linuxArm32Hfp( name: String = "linuxArm32Hfp", configure: KotlinNativeTarget.() -> Unit = { } @@ -470,7 +504,6 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP @Deprecated(DEPRECATED_TARGET_MESSAGE, level = DeprecationLevel.ERROR) - @Suppress("DEPRECATION_ERROR") fun linuxMips32( name: String = "linuxMips32", configure: KotlinNativeTarget.() -> Unit = { } @@ -500,7 +533,6 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP @Deprecated(DEPRECATED_TARGET_MESSAGE, level = DeprecationLevel.ERROR) - @Suppress("DEPRECATION_ERROR") fun linuxMipsel32( name: String = "linuxMipsel32", configure: KotlinNativeTarget.() -> Unit = { } @@ -530,7 +562,6 @@ interface KotlinTargetContainerWithPresetFunctions : KotlinTargetsContainerWithP @Deprecated(DEPRECATED_TARGET_MESSAGE, level = DeprecationLevel.ERROR) - @Suppress("DEPRECATION_ERROR") fun wasm32( name: String = "wasm32", configure: KotlinNativeTarget.() -> Unit = { }