diff --git a/libraries/tools/kotlin-gradle-plugin/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin/build.gradle.kts index 8b549fbd2a9..2154fbd5422 100644 --- a/libraries/tools/kotlin-gradle-plugin/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin/build.gradle.kts @@ -91,8 +91,10 @@ dependencies { if (!kotlinBuildProperties.isInJpsBuildIdeaSync) { val functionalTestImplementation by configurations.getting + val functionalTestCompileOnly by configurations.getting functionalTestImplementation("com.android.tools.build:gradle:7.2.1") functionalTestImplementation("com.android.tools.build:gradle-api:7.2.1") + functionalTestCompileOnly("com.android.tools:common:30.2.1") functionalTestImplementation(gradleKotlinDsl()) functionalTestImplementation(project(":kotlin-gradle-plugin-kpm-android")) functionalTestImplementation(project(":kotlin-tooling-metadata")) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/AndroidGradlePluginVersion.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/AndroidGradlePluginVersion.kt new file mode 100644 index 00000000000..d260a6d3463 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/AndroidGradlePluginVersion.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2010-2022 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. + */ + +@file:Suppress("DuplicatedCode", "FunctionName") + +package org.jetbrains.kotlin.gradle.plugin + +import com.android.Version +import java.io.Serializable +import java.util.* + +internal fun AndroidGradlePluginVersion(versionString: String): AndroidGradlePluginVersion { + return AndroidGradlePluginVersionOrNull(versionString) + ?: throw IllegalArgumentException("Invalid Android Gradle Plugin version: $versionString") +} + +internal fun AndroidGradlePluginVersionOrNull(versionString: String): AndroidGradlePluginVersion? { + val baseVersion = versionString.split("-", limit = 2)[0] + val classifier = versionString.split("-", limit = 2).getOrNull(1) + + val baseVersionSplit = baseVersion.split(".") + if (!(baseVersionSplit.size == 2 || baseVersionSplit.size == 3)) return null + + return AndroidGradlePluginVersion( + major = baseVersionSplit[0].toIntOrNull() ?: return null, + minor = baseVersionSplit[1].toIntOrNull() ?: return null, + patch = baseVersionSplit.getOrNull(2)?.let { it.toIntOrNull() ?: return null } ?: 0, + classifier = classifier + ) +} + +internal data class AndroidGradlePluginVersion( + val major: Int, + val minor: Int, + val patch: Int = 0, + val classifier: String? = null +) : Comparable, Serializable { + override fun compareTo(other: AndroidGradlePluginVersion): Int { + if (this === other) return 0 + (this.major - other.major).takeIf { it != 0 }?.let { return it } + (this.minor - other.minor).takeIf { it != 0 }?.let { return it } + (this.patch - other.patch).takeIf { it != 0 }?.let { return it } + + if (this.classifier == null && other.classifier == null) return 0 + if (this.classifier == null) return 1 + if (other.classifier == null) return -1 + + val thisClassifierLowercase = this.classifier.toLowerCase(Locale.ROOT) + val otherClassifierLowercase = other.classifier.toLowerCase(Locale.ROOT) + if (thisClassifierLowercase == otherClassifierLowercase) return 0 + return thisClassifierLowercase.compareTo(otherClassifierLowercase) + } + + override fun toString(): String { + return "$major.$minor.$patch" + if (classifier != null) "-$classifier" else "" + } + + companion object { + /** + * The currently applied/accessible Android Gradle Plugin version + */ + val current: AndroidGradlePluginVersion? = try { + AndroidGradlePluginVersion(Version.ANDROID_GRADLE_PLUGIN_VERSION) + } catch (_: LinkageError) { + null + } + } +} + +internal operator fun AndroidGradlePluginVersion.compareTo(versionString: String): Int { + return this.compareTo(AndroidGradlePluginVersion(versionString)) +} + +internal fun AndroidGradlePluginVersion?.isAtLeast(versionString: String): Boolean { + if (this == null) return false + return this >= AndroidGradlePluginVersion(versionString) +} + +internal fun AndroidGradlePluginVersion?.isAtLeast(version: AndroidGradlePluginVersion): Boolean { + if (this == null) return false + return this >= version +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/AndroidGradlePluginVersionTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/AndroidGradlePluginVersionTest.kt new file mode 100644 index 00000000000..e58a0619855 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/AndroidGradlePluginVersionTest.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2022 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. + */ + +@file:Suppress("FunctionName") + +package org.jetbrains.kotlin.gradle + +import org.jetbrains.kotlin.gradle.plugin.AndroidGradlePluginVersion +import org.jetbrains.kotlin.gradle.plugin.AndroidGradlePluginVersionOrNull +import org.jetbrains.kotlin.gradle.plugin.isAtLeast +import org.junit.Test +import kotlin.test.* + +class AndroidGradlePluginVersionTest { + + @Test + fun `test - AndroidGradlePluginVersion current - matches AGP version`() { + assertEquals(com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION, assertNotNull(AndroidGradlePluginVersion.current).toString()) + } + + @Test + fun `test - compare`() { + assertTrue(AndroidGradlePluginVersion("3.6") <= AndroidGradlePluginVersion("3.6")) + assertTrue(AndroidGradlePluginVersion("3.6") >= AndroidGradlePluginVersion("3.6")) + assertTrue(AndroidGradlePluginVersion("4.2") > AndroidGradlePluginVersion("3.6")) + assertTrue(AndroidGradlePluginVersion("4.2") < AndroidGradlePluginVersion("7.2.1")) + assertTrue(AndroidGradlePluginVersion("7.0.0-alpha01") < AndroidGradlePluginVersion("7.0.0-alpha02")) + assertTrue(AndroidGradlePluginVersion("7.0.0") > AndroidGradlePluginVersion("7.0.0-alpha02")) + } + + @Test + fun `test - invalid version string`() { + assertNull(AndroidGradlePluginVersionOrNull("x")) + assertFailsWith { AndroidGradlePluginVersion("x") } + } + + + @Test + fun `test - atLeast`() { + assertFalse(null.isAtLeast("1.0")) + assertTrue(AndroidGradlePluginVersion("1.0").isAtLeast("1.0")) + assertTrue(AndroidGradlePluginVersion("1.0").isAtLeast(AndroidGradlePluginVersion("1.0"))) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-tooling-core/src/main/kotlin/org/jetbrains/kotlin/tooling/core/KotlinToolingVersion.kt b/libraries/tools/kotlin-tooling-core/src/main/kotlin/org/jetbrains/kotlin/tooling/core/KotlinToolingVersion.kt index 8fa98bff0f0..fe4e49a80a8 100644 --- a/libraries/tools/kotlin-tooling-core/src/main/kotlin/org/jetbrains/kotlin/tooling/core/KotlinToolingVersion.kt +++ b/libraries/tools/kotlin-tooling-core/src/main/kotlin/org/jetbrains/kotlin/tooling/core/KotlinToolingVersion.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("FunctionName") +@file:Suppress("FunctionName", "DuplicatedCode") package org.jetbrains.kotlin.tooling.core