diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 9bd0a9444ec..8d2081f4af3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -42,6 +42,8 @@ import org.gradle.api.file.FileCollection import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import java.util.ServiceLoader import org.gradle.api.logging.* +import java.net.URL +import java.util.jar.Manifest val DEFAULT_ANNOTATIONS = "org.jebrains.kotlin.gradle.defaultAnnotations" @@ -267,6 +269,14 @@ open class KotlinAndroidPlugin [Inject] (val scriptHandler: ScriptHandler, val t val project = p0 as ProjectInternal val ext = project.getExtensions().getByName("android") as BaseExtension + val version = loadAndroidPluginVersion() + if (version != null) { + val minimalVersion = "1.1.0" + if (compareVersionNumbers(version, minimalVersion) < 0) { + throw IllegalStateException("Kotlin: Unsupported version of com.android.tools.build:gradle plugin: version $minimalVersion or higher should be used with kotlin-android plugin") + } + } + ext.getSourceSets().all(Action { sourceSet -> if (sourceSet is HasConvention) { val sourceSetName = sourceSet.getName() @@ -469,3 +479,78 @@ open class GradleUtils(val scriptHandler: ScriptHandler, val project: ProjectInt resolveDependencies(kotlinPluginArtifactCoordinates(artifact)) public fun resolveJsLibrary(): File = resolveDependencies(kotlinJsLibraryCoordinates()).first() } + +//copied from BasePlugin.getLocalVersion +private fun loadAndroidPluginVersion(): String? { + try { + val clazz = javaClass() + val className = clazz.getSimpleName() + ".class" + val classPath = clazz.getResource(className).toString() + if (!classPath.startsWith("jar")) { + // Class not from JAR, unlikely + return null + } + val manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF"; + + val jarConnection = URL(manifestPath).openConnection(); + jarConnection.setUseCaches(false); + val jarInputStream = jarConnection.getInputStream(); + val attr = Manifest(jarInputStream).getMainAttributes(); + jarInputStream.close(); + return attr.getValue("Plugin-Version"); + } catch (t: Throwable) { + return null; + } +} + +//Copied from StringUtil.compareVersionNumbers +private fun compareVersionNumbers(v1: String?, v2: String?): Int { + if (v1 == null && v2 == null) { + return 0 + } + if (v1 == null) { + return -1 + } + if (v2 == null) { + return 1 + } + + val pattern = "[\\.\\_\\-]".toRegex() + val part1 = v1.split(pattern) + val part2 = v2.split(pattern) + + var idx = 0 + while (idx < part1.size() && idx < part2.size()) { + val p1 = part1[idx] + val p2 = part2[idx] + + val cmp: Int + if (p1.matches("\\d+") && p2.matches("\\d+")) { + cmp = p1.toInt().compareTo(p2.toInt()) + } else { + cmp = part1[idx].compareTo(part2[idx]) + } + if (cmp != 0) return cmp + idx++ + } + + if (part1.size() == part2.size()) { + return 0 + } else { + val left = part1.size() > idx + val parts = if (left) part1 else part2 + + while (idx < parts.size()) { + val p = parts[idx] + val cmp: Int + if (p.matches("\\d+")) { + cmp = Integer(p).compareTo(0) + } else { + cmp = 1 + } + if (cmp != 0) return if (left) cmp else -cmp + idx++ + } + return 0 + } +} \ No newline at end of file