Share
Embed
Groovy to Kotlin in Buildscripts (Kotlin Night Berlin March 2018)
Pros and cons of migrating build scripts from Groovy to Kotlin. Some examples and how the DSL works under the hood.
Talk recording:
https://www.youtube.com/watch?v=BAuP5Bfp-kk
Nelson Osacky
March 15, 2018
Transcript
81 slides
-
Pros • Type safety • Auto complete • Kotlin Cons
• Slower builds • Less examples • Pre-release state • Source digging -
Pros • type safety • better auto complete • kotlin
Cons • slower builds • less examples • pre-release state • source digging -
apply plugin: 'java-library' apply plugin: 'kotlin' apply plugin: 'com.android.library' targetCompatibility
= JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8 dependencies { testCompile deps.junit compileOnly deps.support.annotations implementation deps.kotlin } -
plugins { `java-library` kotlin("jvm") id("com.android.library") }A java { targetCompatibility =
JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8 }B dependencies { testImplementation(deps("junit")) compileOnly((deps("support") as Map<*, *>) ["annotations"].toString()) }C -
/** * Applies the given Kotlin plugin [module]. * *
For example: `plugins { kotlin("jvm") version "1.2.21" }` * * @param module simple name of the Kotlin Gradle plugin module, for example "jvm", "android", "kapt", "plugin.allopen" etc... */ fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec = id("org.jetbrains.kotlin.$module") org.gradle.kotlin.dsl.KotlinDependencyExtensions.kt -
""" /** * Applies the given Kotlin plugin [module]. *
* For example: `plugins { kotlin("jvm") version "$embeddedKotlinVersion" }` * * Visit the [plugin portal](https://plugins.gradle.org/search? term=org.jetbrains.kotlin) to see the list of available plugins. * * @param module simple name of the Kotlin Gradle plugin module, for example "jvm", "android", "kapt", "plugin.allopen" etc... */ fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec = id(“org.jetbrains.kotlin.${‘$’}module”) """ buildSrc/src/main/kotlin/codegen/GenerateKotlinDependencyExtensions.kt -
val generateKotlinDependencyExtensions by task<GenerateKotlinDependencyExtensions> { val publishedPluginsVersion: String by rootProject.extra
outputFile = File(apiExtensionsOutputDir, "org/gradle/kotlin/dsl/ KotlinDependencyExtensions.kt") embeddedKotlinVersion = kotlinVersion kotlinDslPluginsVersion = publishedPluginsVersion kotlinDslRepository = kotlinRepo } provider/build.gradle.kts -
/** * The builtin Gradle plugin implemented by [org.gradle.api.plugins.JavaLibraryPlugin]. */
inline val PluginDependenciesSpec.`java-library`: PluginDependencySpec get() = id("org.gradle.java-library") BuiltInPluginExtensions.kt -
internal fun generateApiExtensionsJar(outputFile: File, gradleJars: Collection<File>, onProgress: () -> Unit)
{ ApiExtensionsJarGenerator(onProgress = onProgress).generate(outputFile, gradleJars) } org.gradle.kotlin.dsl.codegen.ApiExtensionsJar.kt -
apply plugin: 'java-library' apply plugin: 'kotlin' targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility
= JavaVersion.VERSION_1_8 dependencies { testImplementation 'junit:junit:4.12' compileOnly 'com.android.support:support- annotations:27.1.0' }A -
plugins { `java-library` kotlin("jvm") } java { targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8 } dependencies { testImplementation("junit:junit:4.12") compileOnly("com.android.support:support- annotations:27.1.0") }A -
apply plugin: 'java-library' apply plugin: 'kotlin' targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility
= JavaVersion.VERSION_1_8 dependencies { testImplementation 'junit:junit:4.12' compileOnly 'com.android.support:support- annotations:27.1.0' }A -
plugins { `java-library` kotlin("jvm") } java { targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8 } dependencies { testImplementation("junit:junit:4.12") compileOnly("com.android.support:support- annotations:27.1.0") }A -
ext.deps = [ 'junit' : "junit:junit:4.12", 'support' : [ 'annotations':
"com.android.support:support-annotations:$ {versions.supportLibrary}", ], ] -
apply plugin: 'java-library' apply plugin: 'kotlin' targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility
= JavaVersion.VERSION_1_8 dependencies { testImplementation deps.junit compileOnly deps.support.annotations implementation deps.kotlin }W -
dependencies { testImplementation deps.junit }Q dependencies { testImplementation(deps("junit")) }W
fun Project.deps(key: String): Any { return (rootProject.ext["deps"] as Map<*, *>)[key]!! }D -
fun Project.deps(key: String): Any { return (rootProject.ext["deps"] as Map<*, *>)[key]!!
}D ext.deps = [ 'junit' : "junit:junit:4.12", 'support' : [ 'annotations': "com.android.support:support-annotations:$ {versions.supportLibrary}", ], ] -
dependencies { testImplementation(deps(“junit")) compileOnly((deps("support") as Map<*, *>)["annotations"].toString()) }A fun Project.deps(key:
String): Any { return (rootProject.ext["deps"] as Map<*, *>)[key]!! }D -
plugins { `java-library` kotlin("jvm") } java { targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8 }A dependencies { testImplementation(deps("junit")) compileOnly((deps("support") as Map<*, *>)["annotations"].toString()) implementation(deps("kotlin")) } -
apply plugin: 'java-library' apply plugin: 'kotlin' targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility
= JavaVersion.VERSION_1_8 dependencies { testImplementation deps.junit compileOnly deps.support.annotations implementation deps.kotlin }W -
plugins { `java-library` kotlin("jvm") } java { targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8 }A dependencies { testImplementation(deps("junit")) compileOnly((deps("support") as Map<*, *>)["annotations"].toString()) implementation(deps("kotlin")) } -
// Groovy ext.isCi = System.getenv("CI") == “true" // Kotlin extra.set("isCi",
System.getenv("CI") == "true") -
// Groovy if (isCi) { // Do stuff on CI
}A // Kotlin if (isCi) { // Do stuff on CI }B -
// Groovy if (isCi) { // Do stuff on CI
}A // Kotlin if (isCi()) { // Do stuff on CI }B val ExtensionAware.isCi : Boolean get() = extra.properties["isCi"].toString().toBoolean() -
• Experiments are fun • Build speeds are slower •
Kotlin DSL is still pre-release • Everything is an extension function -
public void setSourceCompatibility(Object value) { setSourceCompatibility(JavaVersion.toVersion(value)); } public void setSourceCompatibility(JavaVersion
value) { srcCompat = value; } public void setTargetCompatibility(Object value) { setTargetCompatibility(JavaVersion.toVersion(value)); } public void setTargetCompatibility(JavaVersion value) { targetCompat = value; } org.gradle.api.JavaPluginConvention.java -
public void apply(ProjectInternal project) { project.getPluginManager().apply(JavaBasePlugin.class); JavaPluginConvention javaConvention = project.getConvention()
.getPlugin(JavaPluginConvention.class); } org.gradle.api.plugins.JavaPlugin.java -
/** * Retrieves the [java][org.gradle.api.plugins.JavaPluginConvention] project convention. */ val Project.`java`:
org.gradle.api.plugins.JavaPluginConvention get() = convention.getPluginByName<org.gradle.api.plugins.JavaPluginConvention>("java") /** * Configures the [java][org.gradle.api.plugins.JavaPluginConvention] project convention. */ fun Project.`java`(configure: org.gradle.api.plugins.JavaPluginConvention.() -> Unit): Unit = configure(`java`) org.gradle.kotlin.dsl.accessors.kt -
java { sourceCompatibility = JavaVersion.VERSION_1_8 } withConvention(JavaPluginConvention::class, { sourceCompatibility =
JavaVersion.VERSION_1_8 }) (this as HasConvention).convention.getPlugin(JavaPluginConvention::class).run { sourceCompatibility = JavaVersion.VERSION_1_8 } -
// Groovy // Ensure the no-op leakcanary dependency is always
used in JVM tests. configurations.all { config -> if (config.name.contains("UnitTest")) { config.resolutionStrategy.eachDependency { details -> if (details.requested.group == "com.squareup.leakcanary" && details.requested.name == "leakcanary-android") { details.useTarget(group: details.requested.group, name: "leakcanary-android-no-op", version: details.requested.version) }A }B }C }D -
// Kotlin // Ensure the no-op leakcanary dependency is always
used in JVM tests. configurations.all { if (name.contains("UnitTest")) { resolutionStrategy.eachDependency { if (requested.group == "com.squareup.leakcanary" && requested.name == “leakcanary-android") { useTarget(mapOf("group" to requested.group, "name" to "leakcanary-android-no-op", "version" to requested.version)) }A }B }C }D -
// Kotlin // Ensure the no-op leakcanary dependency is always
used in JVM tests. configurations.all { if (name.contains("UnitTest")) { resolutionStrategy.eachDependency { if (requested.group == "com.squareup.leakcanary" && requested.name == “leakcanary-android") { useTarget(mapOf("group" to requested.group, "name" to "leakcanary-android-no-op", "version" to requested.version)) }A }B }C }D -
// Groovy // Ensure the no-op leakcanary dependency is always
used in JVM tests. configurations.all { config -> if (config.name.contains("UnitTest")) { config.resolutionStrategy.eachDependency { details -> if (details.requested.group == "com.squareup.leakcanary" && details.requested.name == "leakcanary-android") { details.useTarget(group: details.requested.group, name: "leakcanary-android-no-op", version: details.requested.version) }A }B }C }D