// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package com.flutter.gradle import com.android.build.api.AndroidPluginVersion import com.android.build.api.variant.AndroidComponentsExtension import org.gradle.api.JavaVersion import org.gradle.api.Project import org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPluginWrapper internal object VersionFetcher { /** * Returns the version of the JVM. */ internal fun getJavaVersion(): JavaVersion = JavaVersion.current() /** * Returns the version of Gradle. */ internal fun getGradleVersion(project: Project): Version { // https://docs.gradle.org/current/kotlin-dsl/gradle/org.gradle.api.invocation/-gradle/index.html#-837060600%2FFunctions%2F-1793262594 val untrimmedGradleVersion: String = project.gradle.gradleVersion // Trim to handle candidate gradle versions (example 7.6-rc-4). This means we treat all // candidate versions of gradle as the same as their base version // (i.e., "7.6"="7.6-rc-4"). return Version.fromString(untrimmedGradleVersion.substringBefore('-')) } /** * Returns the version of the Android Gradle plugin. */ internal fun getAGPVersion(project: Project): AndroidPluginVersion? { val androidPluginVersion: AndroidPluginVersion? = project.extensions .findByType( AndroidComponentsExtension::class.java )?.pluginVersion return androidPluginVersion } /** * Returns the version of the Kotlin Gradle plugin. */ internal fun getKGPVersion(project: Project): Version? { // TODO(gmackall): AGP has a getKotlinAndroidPluginVersion(), and KGP has a // getKotlinPluginVersion(). Consider replacing this implementation with one of // those. val kotlinVersionProperty = "kotlin_version" val firstKotlinVersionFieldName = "pluginVersion" val secondKotlinVersionFieldName = "kotlinPluginVersion" // This property corresponds to application of the Kotlin Gradle plugin in the // top-level build.gradle file. if (project.hasProperty(kotlinVersionProperty)) { return Version.fromString(project.properties[kotlinVersionProperty] as String) } val kotlinPlugin = project.plugins .findPlugin(KotlinAndroidPluginWrapper::class.java) // Partial implementation of getKotlinPluginVersion from the comment above. var versionString: String? = kotlinPlugin?.pluginVersion if (!versionString.isNullOrEmpty()) { return Version.fromString(versionString) } // Fall back to reflection. val versionField = kotlinPlugin?.javaClass?.kotlin?.members?.firstOrNull { it.name == firstKotlinVersionFieldName || it.name == secondKotlinVersionFieldName } versionString = versionField?.call(kotlinPlugin) as String? return if (versionString == null) { null } else { Version.fromString(versionString) } } } /** * Helper class to parse the versions that are provided as plain strings (Gradle, Kotlin) and * perform easy comparisons. All versions will have a major, minor, and patch value. These values * default to 0 when they are not provided or are otherwise unparseable. * For example the version strings "8.2", "8.2.2hfd", and "8.2.0" would parse to the same version. */ internal class Version( val major: Int, val minor: Int, val patch: Int ) : Comparable { companion object { fun fromString(version: String): Version { val asList: List = version.split(".") val convertedToNumbers: List = asList.map { it.toIntOrNull() ?: 0 } return Version( major = convertedToNumbers.getOrElse(0) { 0 }, minor = convertedToNumbers.getOrElse(1) { 0 }, patch = convertedToNumbers.getOrElse(2) { 0 } ) } } override fun compareTo(other: Version): Int { if (major != other.major) { return major - other.major } if (minor != other.minor) { return minor - other.minor } if (patch != other.patch) { return patch - other.patch } return 0 } override fun equals(other: Any?): Boolean = other is Version && compareTo(other) == 0 override fun hashCode(): Int = major.hashCode() or minor.hashCode() or patch.hashCode() override fun toString(): String = "$major.$minor.$patch" }