[Michael Pustovit] Gradle scripts in Kotlin: is it cool?

[Michael Pustovit] Gradle scripts in Kotlin: is it cool?

Presentation from GDG DevFest Ukraine 2017 - the biggest community-driven Google tech conference in the CEE.

Learn more at: https://devfest.gdg.org.ua

3a6de6bc902de7f75c0e753b3202ed52?s=128

Google Developers Group Lviv

October 14, 2017
Tweet

Transcript

  1. Gradle scripts in Kotlin is it cool?

  2. #dfua Plan for next ~35 minutes 1. Groovy Gradle DSL

    magic 2. Kotlin DSL remedy 3. Demo (groovy -> kotlin) 1 2 3
  3. #dfua Gradle is awesome!

  4. #dfua It builds your project automagically

  5. #dfua But it uses too much magic sometimes

  6. #dfua • Syntactic sugar • Dynamic nature of Groovy Sources

    of magic
  7. #dfua apply plugin: 'java’ version '1.0-SNAPSHOT' sourceCompatibility = 1.8 repositories

    { mavenCentral() } dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } task hello { println "Hello world!" }
  8. #dfua Parentheses apply plugin: 'java’ apply(plugin: 'java’)

  9. #dfua Named parameters testCompile group: 'junit', name: 'junit', version: '4.12'

    testCompile([group: 'junit', name: 'junit', version: '4.12'])
  10. #dfua Lambda as last parameter configure(task1, task2) { doSomething() }

    configure(task1, task2, { doSomething() })
  11. #dfua Abstract Syntax Tree (AST) transformation task hello { println

    "Hello world!" } task('hello', { println "Hello world!" })
  12. #dfua apply(plugin: 'java') version('1.0-SNAPSHOT') sourceCompatibility = 1.8 repositories({ mavenCentral() })

    dependencies({ testCompile([group: 'junit', name: 'junit', version: '4.12']) }) task('hello', { println "Hello world!" })
  13. #dfua Groovy is dynamic

  14. #dfua Gradle build stages 1. Initialization 2. Configuration 3. Execution

    1 2 3
  15. #dfua Init Config Exec Project object Tasks A B C

    >gradle B
  16. #dfua Gradle is about plugins Gradle core can do nothing

    All functions from plugins
  17. #dfua Plugins class GreetingPlugin implements Plugin<Project> { void apply(Project project)

    { project.task('hello') { doLast { println 'Hello from the GreetingPlugin' } } } }
  18. #dfua Plugin configuration Plugins are configured by extensions

  19. #dfua Plugins class GreetingPluginExtension { String message } class GreetingPlugin

    implements Plugin<Project> { void apply(Project prj) { def ext = prj.extensions.create('greeting', GreetingPluginExtension) project.task('hello') { doLast { println ext.message }} } }
  20. #dfua Plugin extension apply plugin: 'org.example.GreetingPlugin' greeting { message "Hello

    world!" } This method doesn’t exist at “compile” time
  21. #dfua class Foo { def methodMissing(String name, def args) {

    return '1' } } assert new Foo().someUnknownMethod(42) == '1' “methodMissing” method
  22. #dfua Problems 1. Too much Groovy specific magic 2. Lack

    of a help from an IDE 3. Late error detection 1 2 3
  23. #dfua • Static typing • Full IDE support Kotlin DSL

    = Solution
  24. #dfua Kotlin feature Kotlin is statically typed and was designed

    with DSL creation in mind
  25. #dfua apply plugin: 'java’ version '1.0-SNAPSHOT' sourceCompatibility = 1.8 repositories

    { mavenCentral() } dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } task hello { println "Hello world!" } Groovy DSL
  26. #dfua apply { plugin("java") } version = "1.0-SNAPSHOT" java.sourceCompatibility =

    JavaVersion.VERSION_1_8 repositories { mavenCentral() } dependencies { testCompile(group = "junit", name = "junit", version = "4.12") } tasks.create("hello", { println("Hello world!") }) Kotlin DSL
  27. #dfua • Dynamic nature of plugins • “Old” plugins •

    Kotlin-Groovy intercommunication Why is it not so easy?
  28. #dfua Current (“old”) plugin system buildscript { repositories { jcenter()

    } def ver = “1.0.0” dependencies { classpath "jfrog…:$ver" } } apply plugin: "com.jfrog…" Dynamic block
  29. #dfua New plugin system pluginManagement { repositories { gradlePluginPortal() }

    } plugins { id "com.jfrog…" version "4.5.2" } Static block Gradle plugins repo
  30. #dfua But there are a lot of plugins that are

    not in the repo yet
  31. #dfua Config Tasks Extensions Serialized snapshot Generated extension handlers

  32. #dfua "conventions": { "base": "org...BasePluginConvention", "java": "org...JavaPluginConvention", ... }, "configurations":

    [ "compile", "Provided", ... ], "extensions": { "ext": "org...ExtraPropertiesExtension", "defaultArtifacts": "org.gradle.api.inter…”, ... } project-schema.json
  33. #dfua val Project.`android`: AppExtension get() = extensions.getByName("android") as AppExtension fun

    Project.`android`(configure: AppExtension.() -> Unit): Unit = extensions.configure("android", configure) Generated code
  34. #dfua > gradle kotlinDslAccessorsSnapshot gradle ├── project-schema.json └── wrapper ├──

    gradle-wrapper.jar └── gradle-wrapper.properties Dynamic > Static workaround
  35. #dfua How to use this workaround 1. Apply a plugin

    but not add an extension yet 2. gradle kotlinDslAccessorsSnapshot 3. Add the extension 1 2 3
  36. #dfua Kotlin DSL + Android • Android plugin is not

    in the repo • Android plugin is tricky • Not supported plugins
  37. #dfua Unsupportable plugins android { playAccountConfigs { defaultAccountConfig { serviceAccountEmail

    = 'a@b.com' pk12File = file('key.p12') } } defaultConfig { // ... } } Triple-T/gradle-play-publisher
  38. #dfua DEMO

  39. #dfua Kotlin extension configuration hack apply { plugin("com.android.application") } //

    android { configure <com.android.build.gradle.AppExtension> { buildToolsVersion("26.0.1") compileSdkVersion(26) } > gradle kotlinDslAccessorsSnapshot
  40. #dfua • Tools are in alpha-beta state • Usable with

    Android projects • Should try - it’s a future Summary
  41. #dfua Sources ❖ Kotlin DSL GitHub repo ❖ Using Gradle

    Script Kotlin for Android ❖ Chicken and egg problem with accessors.kt ❖ Gradle and Kotlin, a personal perspective ❖ Compile time metaprogramming in Groovy ❖ Gradle tip #2: understanding syntax
  42. Thank you! Questions?