詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

Fork me on GitHub

sbt の依存ライブラリを一括 ghq get する

Scala を書くときは IntelliJ Idea みたいな IDE を使っていればドキュメントを確認しやすいのだけど、やっぱ手慣れたものを使いたい。というわけでだいたいの時間はテキストエディタ(Vim)を使っている。そういう時、ソースコードが手元にあると開発の助けになる。

updateClassifiers タスクを使うことですべての(推移的)依存をダウンロードできるらしいが、この場合ファイルは ~/.ivy2/cache/{organization}/{module}/docs/{artifact}-{revision}-javadoc.jar といった場所に保存される。IDE か何かを使ったら閲覧できるのだろうけど、普段使いでは jar 形式で置かれるのは少し面倒だ。

公開されているプロジェクトは全部 ghq という自作ツールでもって手元に整理された状態でクローンするようにしているので、Scala/Java のソースコードもこれにのっとって手元に置きたい。

というわけで sbt プラグインを書いたという話です: sbt-ghq-get-dependencies

使い方

これは性質的に各プロジェクトのプラグインとして設定するよりは、グローバルなところに置くのが良いでしょう。

~/.sbt/0.13/plugins/ghq.sbt みたいなファイルを作って以下のように書く。

resolvers += Resolver.url("bintray-motemen-sbt-plugins", url("https://dl.bintray.com/motemen/sbt-plugins"))(Resolver.ivyStylePatterns)

addSbtPlugin("com.github.motemen" % "sbt-ghq-get-dependencies" % "0.2.0")

sbt から使えるキーは以下のふたつ。

  • ghqGetDependencies …… TaskKey[Unit]。現在のプロジェクトの(直接の)依存ライブラリの SCM リポジトリを探してきて、あれば ghq get する。
  • ghqFilterModule …… SettingKey[sbt.ModuleID => Boolean]。依存モジュールを ghq get すべきかどうかを判断する関数。デフォルトでは configurationsNoneSome("test") であるものだけダウンロード対象とする。

リポジトリの URL は ~/.ivy2/cache 以下の ivy-*.xml.original ファイルに書かれているものを使用するので、あらかじめ update しておく必要がある。

実行するとこんな感じ。

> ghqGetDependencies
[info] org.scala-lang#scala-library;2.11.7 :: git://github.com/scala/scala.git
    exists /Users/motemen/dev/src/github.com/scala/scala
[info] org.scala-lang#scala-library;2.11.7 :: git://github.com/scala/scala.git
    exists /Users/motemen/dev/src/github.com/scala/scala
[info] org.scalatra#scalatra_2.11;2.4.0 :: git://github.com/scalatra/scalatra.git
    exists /Users/motemen/dev/src/github.com/scalatra/scalatra
[info] org.scalatra#scalatra-scalate_2.11;2.4.0 :: git://github.com/scalatra/scalatra.git
    exists /Users/motemen/dev/src/github.com/scalatra/scalatra
[info] org.scalatra#scalatra-scalatest_2.11;2.4.0 :: git://github.com/scalatra/scalatra.git
    exists /Users/motemen/dev/src/github.com/scalatra/scalatra
[info] org.scalaj#scalaj-http_2.11;1.1.6 :: git@github.com:scalaj/scalaj-http.git
    exists /Users/motemen/dev/src/github.com/scalaj/scalaj-http
[info] org.json4s#json4s-jackson_2.11;3.3.0 :: git://github.com/json4s/json4s.git
    exists /Users/motemen/dev/src/github.com/json4s/json4s
[info] org.scalaz#scalaz-core_2.11;7.1.4 :: git@github.com:scalaz/scalaz.git
    exists /Users/motemen/dev/src/github.com/scalaz/scalaz
[info] org.scalaz#scalaz-concurrent_2.11;7.1.4 :: git@github.com:scalaz/scalaz.git
    exists /Users/motemen/dev/src/github.com/scalaz/scalaz
[info] com.typesafe.slick#slick_2.11;3.1.1 :: git@github.com:slick/slick.git
    exists /Users/motemen/dev/src/github.com/slick/slick
[info] org.postgresql#postgresql;9.4.1207 :: (not found)
[info] com.github.tarao#slick-jdbc-extension_2.11;0.0.3 :: git@github.com:tarao/slick-jdbc-extension-scala.git
    exists /Users/motemen/dev/src/github.com/tarao/slick-jdbc-extension-scala
[info] net.debasishg#redisclient_2.11;3.1 :: git@github.com:debasishg/scala-redis.git
    exists /Users/motemen/dev/src/github.com/debasishg/scala-redis
[info] org.pegdown#pegdown;1.6.0 :: git@github.com:sirthias/pegdown.git
     clone ssh://git@github.com/sirthias/pegdown.git -> /Users/motemen/dev/src/github.com/sirthias/pegdown
       git clone ssh://git@github.com/sirthias/pegdown.git /Users/motemen/dev/src/github.com/sirthias/pegdown
Cloning into '/Users/motemen/dev/src/github.com/sirthias/pegdown'...
[info] org.mockito#mockito-core;2.0.36-beta :: (not found)
[success] Total time: 10 s, completed 2016/02/08 1:28:30

プラグインの依存を取得する

reload plugins でプラグインのプロジェクトに移動した後、ghqGetDependencies することで addSbtPlugin したライブラリのソースコードを取得できる。reload return で元のプロジェクトに復帰。

sbt Reference Manual — Plugins に書いてあるけど偶然発見できたという感じだった。知らなかった……。

sbt で Vim のスワップファイルが watch されるのを抑制する

Scala の話。sbt~compile とかしてるときに Vim で新しいファイルを編集しはじめるとコンパイルが始まってなんだこりゃとなることがある。いまいちまとまった情報がないのでここに記しておく。

こういう場合 watchSources というキーに変更を加えてやるとよい。

グローバルに適用するために、~/.sbt/0.13/global.sbt などのファイルに以下のように記述する:

watchSources ~= {
  _.filterNot {
    f =>
      f.isDirectory ||
        """^\..*\.sw.$""".r.findFirstIn(f.getName).isDefined
  }
}

場合によっては ~/.sbt/0.13.9 以下に配置する必要があるかもしれない。

~=

どういう訳かはわからないけれど 0.13.x 系のドキュメントには ~= の説明がない。0.12.x 系には載っている。

More Kinds of Setting — sbt Documentation

参考

Play Framework で `rails runner` 的なことを実現する

Play Framework 2.2.x の話です。分かりよいだろうというので rails runner を引き合いに出したのだけど、つまり何をやりたいかというと、アプリケーション本体のコード(Play も含めて)を利用して、オペレーションやメンテナンス用のタスク(バッチ処理)を書きたい。初心者なのでフレームワークに乗っからないとデータベースへの接続もできないのです。

適当に Scala の object を作って sbt runMain してやれば任意のコードを実行することはできるけれど、最終的にビルドしたときにアプリケーション本体には含めたくないので、分けて置いておきたい。フレームワークにそういうサポートがあるのじゃないかと考えていろいろ調べてみたけれど結局わからなかったので、こういう風にやってみた。

  • "tasks" というディレクトリを作り、ここに実行したいタスクを main() を備えた object として書く。
  • sbt の設定(build.sbt)で、tasks という、ルートプロジェクトに依存したサブプロジェクトを定義する。
  • 個々のタスクは sbt 'tasks/runMain {taskObject} {args}' で実行する。

不完全な例を挙げると、以下のようになります:

`rails runner` in Play framework

ウェブアプリケーションとして稼働していない場合に Play の API を叩きたいときには、play.core.StaticApplication というのを使えばよいらしいです。また、暗黙の Application を導入するために current をインポートするのと、最後に Play.stop() するのを忘れずに。

はてなで一緒に働きませんか?