GrapeでGparsを使おうとすると依存性が解決しきれなくて困った件

もうGroovyなライブラリは、Grapeを使うのがアタリマエですよね。そうですよね。


というわけで、2009/12/04にTwitterで0.9-beta1がでたよ!というTweetをみかけたので、さっそくGrapeで試してみました。

// Fibonacci
def fib = { n -> return (n == 0) ?
              1 :
              (n == 1) ?
                  1 :
                  call(n - 1) + call(n - 2)
}
 
@Grab("org.codehaus.gpars:gpars:0.9-beta-1")
import groovyx.gpars.actor.Actor
import static groovyx.gpars.actor.Actors.actor
 
def list = [3, 10, 15, 2, 5]
def calc = actor {
  def count = 1
  loop {
    react { map ->
      println "fib(${map.num}): ${map.result}"
      reply()
      
      count++
      if (count > list.size()) stop()
    }
  }
}
 
list.each { num ->
  actor {
    def result = fib(num)
    calc.send([num:num, result:result])
    react {
      stop()
    }
  }
  
}
 
calc.join()

と、@Grabアノテーションを指定したコードを書いて、実行してみると・・・

$ groovy fib_actor.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during conversion: Error grabbing Grapes -- [unresolved dependency: org.grails#grails-docs;1.2.0.BUILD-SNAPSHOT: not found, unresolved dependency: org.jboss.netty#netty;3.1.5.GA: not found]

java.lang.RuntimeException: Error grabbing Grapes -- [unresolved dependency: org.grails#grails-docs;1.2.0.BUILD-SNAPSHOT: not found, unresolved dependency: org.jboss.netty#netty;3.1.5.GA: not found]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

一部の依存ライブラリがサードパーティMavenリポジトリに入っていたため、依存性解決が失敗してしまいました。
なんということでしょう。



ということをtwitterでぼやいたら、Gparsのコミッタの@vaclav_pech氏が反応してくれました。
GparsのコミッタはNice Guyなんだぜ?


というわけで、怪しい英語は見ないふりをしつつ、http://gpars.codehaus.org/Integration にある、実はnobeans製だったりするgrapeConfig.xmlのサンプルを、そのまま$HOME/.groovy配下に格納すれば*1、それ以降は普通にGparsがGrape経由で利用できます。素敵。


ちなみに、 このサンプルコードはものすごいハイウエストな方(id:nbqx69)のブログのサンプルをベースにしてます。あしからず。


でも、groovy1.7-RC2から@GrabResolverアノテーションを使えるようになったから、grapeConfig.xmlなんてもういじる必要がなくなるんですよね。
@GrabResolverを使えば、スクリプト内で見に行くMavenリポジトリを追加できます。

// ...snip
@GrabResolver(name="jboss", root="http://repository.jboss.org/maven2/")
@GrabResolver(name="codehaus.snapshot", root="http://snapshots.repository.codehaus.org/")
@Grab("org.codehaus.gpars:gpars:0.9-beta-1")
import groovyx.gpars.actor.Actor
// ...snip

と書くだけでOK.
スクリプトローカルでJarの取得元を指定できます。

$ groovy fib_actor.groovy 
fib(3): 3
fib(2): 2
fib(5): 8
fib(10): 89
fib(15): 987


これで、よりポータブルなスクリプトがかけますね!
素晴らしい!


ただ、Gparsについていえば、そもそも今回依存性解決に失敗したライブラリは、実行時には必要なさそうな雰囲気なので、そのうちこんな小細工はいらなくなるかもしれません。

*1:自分が手動で作ってなければデフォルトでは存在しない