From b745d1617f3ce6ca95be3a09a96f5cadff1f4f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Doln=C3=ADk?= Date: Fri, 10 May 2024 16:52:06 +0200 Subject: [PATCH] Fix KGP version detection in projects that provide it from buildSrc. --- .../skie/plugin/SkieGradlePluginApplier.kt | 9 +- .../skie/plugin/SkieInternalExtension.kt | 23 ++-- .../skie/plugin/util/KotlinVersionResolver.kt | 71 ----------- .../plugin/util/SkieKotlinVariantResolver.kt | 116 ++++++++++++++++++ 4 files changed, 134 insertions(+), 85 deletions(-) delete mode 100644 SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/util/KotlinVersionResolver.kt create mode 100644 SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/util/SkieKotlinVariantResolver.kt diff --git a/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/SkieGradlePluginApplier.kt b/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/SkieGradlePluginApplier.kt index d90ecb8f..167f30bc 100644 --- a/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/SkieGradlePluginApplier.kt +++ b/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/SkieGradlePluginApplier.kt @@ -21,12 +21,13 @@ object SkieGradlePluginApplier { fun apply(project: Project) { // We need to register the extensions here, so that Gradle knows the type of it in the build script. SkieExtension.createExtension(project) - SkieInternalExtension.createExtension(project) ?: return - project.configureSkieGradlePlugin() + SkieInternalExtension.withExtension(project) { + project.configureSkieGradlePlugin() - project.afterEvaluate { - project.configureSkieCompilerPlugin() + project.afterEvaluate { + project.configureSkieCompilerPlugin() + } } } diff --git a/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/SkieInternalExtension.kt b/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/SkieInternalExtension.kt index 3fb4984d..ecd9866f 100644 --- a/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/SkieInternalExtension.kt +++ b/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/SkieInternalExtension.kt @@ -3,7 +3,7 @@ package co.touchlab.skie.plugin import co.touchlab.skie.plugin.configuration.skieExtension import co.touchlab.skie.plugin.shim.KgpShim import co.touchlab.skie.plugin.shim.KgpShimLoader -import co.touchlab.skie.plugin.util.KotlinVersionResolver +import co.touchlab.skie.plugin.util.SkieKotlinVariantResolver import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project import javax.inject.Inject @@ -22,16 +22,19 @@ abstract class SkieInternalExtension @Inject constructor( companion object { - fun createExtension(project: Project): SkieInternalExtension? { - val kotlinVersion = KotlinVersionResolver.resolve(project) ?: return null - val kgpShim = KgpShimLoader.load(kotlinVersion, project) ?: return null + fun withExtension(project: Project, action: (SkieInternalExtension) -> Unit) { + SkieKotlinVariantResolver.withSkieKotlinVersion(project) { kotlinVersion -> + val kgpShim = KgpShimLoader.load(kotlinVersion, project) ?: return@withSkieKotlinVersion - return project.extensions.create( - "skieInternal", - SkieInternalExtension::class.java, - kotlinVersion, - kgpShim, - ) + val extension = project.extensions.create( + "skieInternal", + SkieInternalExtension::class.java, + kotlinVersion, + kgpShim, + ) + + action(extension) + } } } } diff --git a/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/util/KotlinVersionResolver.kt b/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/util/KotlinVersionResolver.kt deleted file mode 100644 index ee6f93b5..00000000 --- a/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/util/KotlinVersionResolver.kt +++ /dev/null @@ -1,71 +0,0 @@ -package co.touchlab.skie.plugin.util - -import co.touchlab.skie.gradle_plugin_impl.BuildConfig -import org.gradle.api.Project - -object KotlinVersionResolver { - - fun resolve(project: Project): String? = - project.getValidKotlinVersion() - - private fun Project.getValidKotlinVersion(): String? { - val kotlinVersion = getKotlinVersionString() - val skieVersion = kotlinVersion?.let { BuildConfig.KOTLIN_TO_SKIE_VERSION[it] } - - if (kotlinGradlePluginVersionOverride != null) { - logger.error( - """ - Warning: - skie.kgpVersion is used to override automatic Kotlin version resolution for SKIE plugin. - Usage of this property in production is highly discouraged as it may lead to non-obvious compiler errors caused by SKIE incompatibility with the used Kotlin compiler version. - """.trimIndent(), - ) - } - - val error = when { - kotlinVersion == null -> { - """ - SKIE could not infer Kotlin plugin version. - Make sure you have Kotlin Multiplatform plugin applied in the same module as SKIE and that the plugin works - for example by calling the link task that produces the Obj-C framework. - If that is the case, then this problem is likely caused by a bug in SKIE - please report it to the SKIE developers. - You can try to workaround this issue by providing the Kotlin version manually via 'skie.kgpVersion' property in your gradle.properties. - """.trimIndent() - } - skieVersion == null -> { - val supportedKotlinVersions = BuildConfig.KOTLIN_TO_SKIE_VERSION.keys.sorted() - - """ - SKIE ${BuildConfig.SKIE_VERSION} does not support Kotlin $kotlinVersion. - Supported versions are: ${supportedKotlinVersions}. - Check if you have the most recent version of SKIE and if so, please wait for the SKIE developers to add support for this Kotlin version. - New Kotlin versions are usually supported within a few days after they are released. - Note that there are no plans for supporting early access versions like Beta, RC, etc. - """.trimIndent() - } - else -> return skieVersion - } - - reportSkieLoaderError(error) - - return null - } - - private fun Project.getKotlinVersionString(): String? = - (project.kotlinGradlePluginVersionOverride ?: project.kotlinGradlePluginVersion ?: project.rootProject.kotlinGradlePluginVersion) - - private val Project.kotlinGradlePluginVersion: String? - get() = kotlinGradlePluginVersionFromClasspathConfiguration() - - private val Project.kotlinGradlePluginVersionOverride: String? - get() = findProperty("skie.kgpVersion") as? String - - private fun Project.kotlinGradlePluginVersionFromClasspathConfiguration(): String? { - val classpathConfiguration = buildscript.configurations.getByName("classpath") - - val artifact = classpathConfiguration.resolvedConfiguration.resolvedArtifacts.singleOrNull { artifact -> - artifact.moduleVersion.id.let { it.group == "org.jetbrains.kotlin" && it.name == "kotlin-gradle-plugin" } - } - - return artifact?.moduleVersion?.id?.version - } -} diff --git a/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/util/SkieKotlinVariantResolver.kt b/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/util/SkieKotlinVariantResolver.kt new file mode 100644 index 00000000..9774d7f4 --- /dev/null +++ b/SKIE/skie-gradle/plugin-impl/src/common/kotlin/co/touchlab/skie/plugin/util/SkieKotlinVariantResolver.kt @@ -0,0 +1,116 @@ +package co.touchlab.skie.plugin.util + +import co.touchlab.skie.gradle_plugin_impl.BuildConfig +import org.gradle.api.Project + +object SkieKotlinVariantResolver { + + fun withSkieKotlinVersion(project: Project, action: (String) -> Unit) { + project.withKotlinVersion { kotlinVersion -> + project.getValidSkieKotlinVersion(kotlinVersion)?.let(action) + } + } + + private fun Project.withKotlinVersion(action: (String) -> Unit) { + raiseVersionOverrideUsageWarningIfNeeded() + + project.getKotlinVersionString()?.let { kotlinVersion -> + action(kotlinVersion) + + return + } + + withKotlinVersionDelayed(action) + } + + private fun Project.withKotlinVersionDelayed(action: (String) -> Unit) { + var kotlinVersion: String? = null + + // Cannot be configureEach otherwise it could crash the project that uses SKIE + plugins.all { + if (kotlinVersion == null) { + kotlinVersion = project.kotlinGradlePluginVersionFromPlugin() + + kotlinVersion?.let(action) + } + } + + afterEvaluate { + if (kotlinVersion == null) { + logger.error( + """ + SKIE could not infer Kotlin plugin version. + Make sure you have Kotlin Multiplatform plugin applied in the same module as SKIE and that the plugin works - for example by calling the link task that produces the Obj-C framework. + If that is the case, then this problem is likely caused by a bug in SKIE - please report it to the SKIE developers. + You can try to workaround this issue by providing the Kotlin version manually via 'skie.kgpVersion' property in your gradle.properties. + """.trimIndent(), + ) + } + } + } + + private fun Project.raiseVersionOverrideUsageWarningIfNeeded() { + if (kotlinGradlePluginVersionOverride != null) { + logger.error( + """ + Warning: + skie.kgpVersion is used to override automatic Kotlin version resolution for SKIE plugin. + Usage of this property in production is highly discouraged as it may lead to non-obvious compiler errors caused by SKIE incompatibility with the used Kotlin compiler version. + """.trimIndent(), + ) + } + } + + private fun Project.getValidSkieKotlinVersion(kotlinVersion: String): String? { + val skieVersion = BuildConfig.KOTLIN_TO_SKIE_VERSION[kotlinVersion] + + if (skieVersion == null) { + val supportedKotlinVersions = BuildConfig.KOTLIN_TO_SKIE_VERSION.keys.sorted() + + reportSkieLoaderError( + """ + SKIE ${BuildConfig.SKIE_VERSION} does not support Kotlin $kotlinVersion. + Supported versions are: ${supportedKotlinVersions}. + Check if you have the most recent version of SKIE and if so, please wait for the SKIE developers to add support for this Kotlin version. + New Kotlin versions are usually supported within a few days after they are released. + Note that there are no plans for supporting early access versions like Beta, RC, etc. + """.trimIndent(), + ) + } + + return skieVersion + } + + private fun Project.getKotlinVersionString(): String? = + (project.kotlinGradlePluginVersionOverride ?: project.kotlinGradlePluginVersion ?: project.rootProject.kotlinGradlePluginVersion) + + private val Project.kotlinGradlePluginVersion: String? + get() = kotlinGradlePluginVersionFromClasspathConfiguration() ?: kotlinGradlePluginVersionFromPlugin() + + private val Project.kotlinGradlePluginVersionOverride: String? + get() = findProperty("skie.kgpVersion") as? String + + private fun Project.kotlinGradlePluginVersionFromClasspathConfiguration(): String? { + val classpathConfiguration = buildscript.configurations.getByName("classpath") + + val artifact = classpathConfiguration.resolvedConfiguration.resolvedArtifacts.singleOrNull { artifact -> + artifact.moduleVersion.id.let { it.group == "org.jetbrains.kotlin" && it.name == "kotlin-gradle-plugin" } + } + + return artifact?.moduleVersion?.id?.version + } + + private fun Project.kotlinGradlePluginVersionFromPlugin(): String? { + try { + val kotlinBasePluginClass = this@SkieKotlinVariantResolver.javaClass.classLoader.loadClass("org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin") + + val plugin = plugins.firstOrNull { kotlinBasePluginClass.isAssignableFrom(it.javaClass) } ?: return null + + return kotlinBasePluginClass.getDeclaredMethod("getPluginVersion").invoke(plugin) as? String + } catch (e: Throwable) { + logger.debug("SKIE could not determine the Kotlin Gradle plugin version directly from Kotlin Gradle plugin because: $e") + + return null + } + } +}