CLOVER🍀

That was when it all began.

Groovyの簡易依存関係管理ツール、Grapeを使ってみる

Groovy 2.0が出ましたね〜。機能的なところはあんまり見てませんが、なんか型チェックとかができるようになったんだとか?それって、Groovyで待ち望まれてたものなんでしょうか?よくわからんです…。

ま、とりあえずバージョンアップはしておきましたと。

ところで、Groovyでビルドや依存関係の管理ツールといえばGradleが有名だと思いますが、自分はそれほどどっぷりGroovyを使っているわけではないので、これを触るのは少し後にして、今はもっと簡易的というか標準で搭載されているGrapeを使ってみようと思います。

Grapeとは?

Apache Ivyを使った、Groovyの標準的なモジュール管理ツールです。Mavenリポジトリをサポートしているので、他のリポジトリからJARファイルなどをダウンロードしてスクリプト中で依存関係を解決しつつ実行することができます。

詳細は、こちらです。
http://groovy.codehaus.org/Grape

まずはサンプル

ここは、Commons Lang3を使ってみましょう。
GrapeTest.groovy

@Grab(group = 'org.apache.commons', module = 'commons-lang3', version = '3.1')
// @Grab('org.apache.commons:commons-lang3:3.1') // => これでもOK
import org.apache.commons.lang3.StringUtils

println(StringUtils.join(args, ', ') + '!')

付けるのは、最小で@Grabアノテーションひとつだけです。各パラメータの意味は、Mavenを使ったことがあればなんとなくわかると思います…。ここでは、Mavenセントラルリポジトリからダウンロードしてくることになります。
とりあえず、実行。

$ groovy GrapeTest.groovy Hello World
Hello, World!

ちなみに、この程度の処理ならCommons Langを使用せずともGroovyの標準機能だけでもちろん実行可能です。そして、それなりに起動にオーバーヘッドもかかってきます。実際、@Grabアノテーションを使用すると、何も使用しない場合に比べて起動がちょっともさっとした感じになります。

@Grabアノテーションが付けられる場所は、import文やクラス宣言、メソッド、プロパティなどなど。さすがに何もないところにアノテーションは使えないので、groovyshなどで使う時はメソッド呼び出しを使ってくれってことらしいですが、ここでは割愛。

バージョン指定はIvyのものをサポートしているので、こういう書き方をしても

@Grab(group = 'org.apache.commons', module = 'commons-lang3', version = '[3,)')

現時点だと、最初の例と同様Commons Lang3 3.1が取得できます。

リポジトリを指定する場合は?

Grapeはデフォルトで、Mavenセントラルリポジトリ、codehause、ibiblio、java.netのリポジトリから依存関係を解決できるようですが、他のリポジトリからライブラリを取得したい場合もあると思います。
参考)
https://github.com/groovy/groovy-core/blob/master/src/main/groovy/grape/defaultGrapeConfig.xml

そんな時は、@GrabResolverアノテーションを使用します。ここでは、Seasar2からちょっと拝借。

@GrabResolver(name = 'The Seasar Foundation Maven2 Repository', root = 'http://maven.seasar.org/maven2')
@Grab('org.seasar.container:s2-framework:2.4.46')
@GrabExclude('junit:junit')
import org.seasar.framework.util.StringUtil
@Grab('org.apache.commons:commons-lang3:3.1')
import org.apache.commons.lang3.StringUtils

println(StringUtils.join(args, ', ') + '!')
println("args isEmpty ? => ${StringUtil.isEmpty(args.join(', '))}")

あと、@GrabExcludeアノテーションで、JUnitは除外しています…。

プロキシ経由で使いたい場合は?

Javaアプリで割と使う、システムプロパティを使用します。
コマンドラインで指定するか

groovy -Dhttp.proxyHost=[プロキシサーバのIPアドレス or ホスト名] -Dhttp.proxyPort=[プロキシサーバのポート] [実行スクリプト名」

環境変数JAVA_OPTSを使用してくれ、だそうで。

JAVA_OPTS = -Dhttp.proxyHost=[プロキシサーバのIPアドレス or ホスト名] -Dhttp.proxyPort=[プロキシサーバのポート]

定義をまとめて書きたい時は

@Grapesアノテーションを使うみたいですよ。

@GrabResolver(name = 'The Seasar Foundation Maven2 Repository', root = 'http://maven.seasar.org/maven2')
@Grapes([
            @Grab('org.apache.commons:commons-lang3:3.1'),
            @Grab('org.seasar.container:s2-framework:2.4.46'),
            @GrabExclude('junit:junit')
        ])
import org.apache.commons.lang3.StringUtils
import org.seasar.framework.util.StringUtil

JDBCドライバを使う時は

システムクラスローダを使うように設定するらしいです。

@GrabConfig(systemClassLoader=true)
@Grab(group='mysql', module='mysql-connector-java', version='5.1.6')

現在Grapeで管理されているライブラリの一覧を見るには

grapeコマンドのlistを使用します。

$ grape list

org.seasar.container s2-framework  [2.4.46]
org.seasar.container s2-container-project  [2.4.46]
ognl ognl  [2.6.9-patch-20090427]
junit junit  [3.8.2]
org.apache.commons commons-lang3  [3.1]
org.apache.commons commons-parent  [22]
org.apache apache  [9]
aopalliance aopalliance  [1.0]
jboss javassist  [3.4.ga]
commons-logging commons-logging  [1.1]

10 Grape modules cached
10 Grape module versions cached

なお、

$ grape install <groupId> <artifactId> [<version>]

でライブラリのインストールもできるみたいですが、スクリプトを実行する時にダウンロードさせる、でいいんじゃないかなぁと…。

ダウンロードしたライブラリは、どこに置かれる?

[ユーザホームディレクトリ]/.groovy/grapesっぽいですね。

$ ll ~/.groovy/grapes/
合計 48
drwxrwxr-x 10 xxxxx xxxxx 4096 Jul  7 20:39 ./
drwxrwxr-x  3 xxxxx xxxxx 4096 Jul  7 19:40 ../
drwxrwxr-x  3 xxxxx xxxxx 4096 Jul  7 20:26 aopalliance/
drwxrwxr-x  3 xxxxx xxxxx 4096 Jul  7 20:27 commons-logging/
drwxrwxr-x  3 xxxxx xxxxx 4096 Jul  7 20:26 jboss/
drwxrwxr-x  3 xxxxx xxxxx 4096 Jul  7 20:27 junit/
drwxrwxr-x  3 xxxxx xxxxx 4096 Jul  7 20:26 ognl/
drwxrwxr-x  3 xxxxx xxxxx 4096 Jul  7 19:57 org.apache/
drwxrwxr-x  4 xxxxx xxxxx 4096 Jul  7 19:57 org.apache.commons/
drwxrwxr-x  4 xxxxx xxxxx 4096 Jul  7 20:26 org.seasar.container/
-rw-rw-r--  1 xxxxx xxxxx  442 Jul  7 20:27 resolved-caller-all-caller-working83.properties
-rw-rw-r--  1 xxxxx xxxxx  599 Jul  7 20:27 resolved-caller-all-caller-working83.xml

とまあ、こんな感じ?割とお手軽に使えるので、いいですね♪