mike-neckのブログ

Java or Groovy or Swift or Golang

kotlinでgradle のスクリプトを書く時に気をつけたい点

f:id:mike_neck:20171113232305p:plain

Gradleは元々Groovyで書かれてたツールで、バージョン2の頃にほぼすべてをJavaに置き換えられたという経緯があるのですが、未だに古い一部の実装ではGroovyでスクリプトを書くことを前提にしている箇所があります(と断言していいかどうかは自信がない)。

maven プラグインuploadArchives まわりもGroovyで書くことを前提としているフシがあり、 MavenDeployer -> MavenPom#project の後のブロックは delegate オブジェクトが groovy.lang.GroovyObject というまさに groovy なDSLになっている

先日、mavenにリリースするライブラリーのdslをkotlinで書いていたが、この部分のdslを最初次のように書いていた。入れ子構造になっている部分を書き始めようとした時に、どのように書くのかわからず、手探りで書いていた。

mavenDeployer {
  pom.project {
    invoke("name", "library-name")
    invoke("packaging", "jar")
    invoke("scm", mapOf(
      "connection" to "scm:git:https://github.com/mike-neck/repository-name",
      "url" to "https://github.com/mike-neck/repository-name"
    ))
  }
}

しかし、この部分、おそらくgroovyの MarkupBuilder を使っていることは想像がついたため、このようなDSLだと次のような望まないpom.xmlが生成されるように思われた。

<name>librry-name</name>
<scm connection="scm:git:https://github.com/mike-neck/repository-name" url="https://github.com/mike-neck/repository-name"/>

というわけで、1〜2時間悩んでいたのだが、kotlin-dslのサンプルにあたってみたところ、すでに解決策が提示されていた。

github.com

GroovyObject を扱う場合は withGroovyBuilder(GroovyBuilderScope.() -> T) という拡張関数を使えば解決できるそうだ。

したがって、次のような dslを書けば、valid な pom.xml が出力される

mavenDeployer {
  pom.project {
    withGroovyBuilder {
      "name" ("library-name")
      "packaging" ("jar")
      "scm" {
        "connection"("scm:git:https://github.com/mike-neck/repository-name")
        "url"("https://github.com/mike-neck/repository-name")
      }
    }
  }
}