Skip to main content

6 posts tagged with "sbt"

View All Tags

· 3 min read

Sublime Text 2にensimeを入れてみたものの、完璧ではない。

Sublime Text 2でensimeを利用してみたが…

■ Use Sublime Text 2 for Scala Development « A Pinoy Programmer in Japanhttp://blog.hugeaim.com/2012/03/22/use-sublime-text-2-for-scala-development/
It seems that the validation is not yet perfect, so I would still use this in combination with an SBT build
こんな記述もあるわけだし、完璧ではないのは承知の上。 エラーがあるのか無いのかよくわからないこともあり、sbtも導入しておくのがよさそう。

· 8 min read

また海藻猫が騒いでいたのを見つけてしまったのが運の尽き…。 [blackbirdpie id="126122863177633793"]

Android開発はやったことがないからわからないけど、Scala + Eclipseは使っているから、簡単に手順を書いておく。

■ teaplanet/sbt-appengine-eclipse - GitHub

https://github.com/teaplanet/sbt-appengine-eclipse以下の手順で作るふたつのbuild.sbtはGitHubに置いといた。

前提

sbtとEclipseを使ってAppEngineの開発を行う。 テストにはspecs2を使うことを想定してるので、specs2がいらない場合は後述のbuild.sbtからspecs2の依存関係消してね。

こんな役割分担で使ってます。 依存関係解決:sbt エディタ:Eclipse コンパイル:Eclipse(, sbt) テスト:Eclipse(, sbt) デバッグ:Eclipse こんな構成で行います。

ライブラリの依存関係の解決はsbtに任せる。ついでにEclipseのプロジェクトファイル(.project)の生成もsbtに任せる。 Eclipseはエディタとして使いつつ、同時にコンパイルも行う。 テストしつつデバッグもEclipseで行ってる。 基本的にどちらを使ってもいいんだけど、個人的にはこうやって使ってる。

依存関係の解決をsbtがやってくれるもんだから、バージョン管理にバイナリが含まれなくて精神衛生上よい。 プロジェクトをコンパイルするにもコンソールだけで済むし(Eclipse不要)。

環境

Mac OS X 10.7.1 Scala 2.9.1 sbt 0.11.0-RC1 Eclipse Indigo

開発環境構築

sbtの入手

■ Index of ivy-snapshots/org.scala-tools.sbt/sbt-launch/0.11.0-RC1http://repo.typesafe.com/typesafe/ivy-snapshots/org.scala-tools.sbt/sbt-launch/0.11.0-RC1/コンパイルしてもいいけど、持ってきた方が楽。今はこれを使ってます。 違うバージョンでも問題ないかもしれないけど、他のバージョンを使ってたらsbteclipseが動かなかった。

sbtのインストール

入手したsbt(sbt-launch.jar)を実行するために ~/bin/sbt ファイルを作成する。
java -Xmx512M -jar `dirname $0`/sbt-launch.jar "$@"
chmod u+x ~/bin/sbt
実行権限付けて、実行できるようにする。

プロジェクト作成

プロジェクトは "ws/sample" に作ることにする。
mkdir -p ws/sample cd ws/sample sbt
これでsbtで必要なファイルが作成され、sbtのプロンプトが表示されているはず。 aboutって入力するとsbtやScalaのバージョンが表示されます。

プロジェクト定義

プロジェクト定義ファイルであるbuild.sbtを作る。 このファイルを作るときはエディタで作ってもいいし、別コンソールからviで作ってもいい。このあともちょくちょくsbtでコマンドを実行するので、sbtプロンプトは残しておいた方が便利だと思う。 ws/sample/build.sbt
name := "sample"

version := "1.0.0"

scalaVersion := "2.9.1"

organization := "teaplanet"

// for Specs2
resolvers ++= Seq("snapshots" at "http://scala-tools.org/repo-snapshots",
"releases" at "http://scala-tools.org/repo-releases",
"releases" at "http://repo1.maven.org/maven2/")

libraryDependencies ++= {
val appEngineVersion = "1.5.5"
Seq(
"com.google.appengine" % "appengine-api-1.0-sdk" % appEngineVersion,
"com.google.appengine" % "appengine-api-stubs" % appEngineVersion % "test",
"com.google.appengine" % "appengine-api-labs" % appEngineVersion % "test",
"com.google.appengine" % "appengine-testing" % appEngineVersion % "test",
"com.google.appengine" % "appengine-tools-sdk" % appEngineVersion % "test",
"org.specs2" %% "specs2" % "1.6.1" % "test",
"org.specs2" %% "specs2-scalaz-core" % "6.0.1" % "test",
"junit" % "junit" % "4.9" % "test"
)
}

build.sbtの空行は大切。

このファイルを作成したら、sbtプロンプトへ戻る。

reload
update

reloadコマンドで更新したファイルを読み込み、updateコマンドで設定を反映する。 初回は依存ライブラリをダウンロードするから時間がかかると思うので、しばし待つ。 ここまででAppEngineの開発が出来る状態になってる。

sbteclipseプラグインを導入する

Eclipseのプロジェクトファイル(.project)を作るためにsbteclipseプラグインを導入する。 ws/sample/project/plugins/build.sbt
resolvers += Classpaths.typesafeResolver

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse" % "1.4.0-RC4")

pluginsディレクトリは無いと思うので作成する。 ここでもbuild.sbtの空行は意味があるので注意。

またsbtプロンプトへ戻ってお約束のコマンド。

reload
update

これでsbteclipseの導入が完了。

ecl[TAB]

と打って "eclipse" と補完されるようであれば正常に導入されてる。

.projectを作るために次のコマンドを実行する。

eclipse create-src

EclipseでScalaを使う準備

■ Scala IDE for Eclipsehttp://www.scala-ide.org/EclipseでScalaを使うためにScala IDE for Eclipseをインストールしておくこと。

Eclipseの設定でbuildmanagerとしてsbtを使う設定ができる。

でも、これが役に立っているかはわかっていない…。

■ Using the Google Plugin for Eclipse - Google App Engine - Google Code

http://code.google.com/intl/en/appengine/docs/java/tools/eclipse.html#Installing_the_Google_Plugin_for_Eclipseライブラリの依存関係はsbtで解決してるので、こっちは必要ないかも。入れてあるけど。

Eclipseをエディタとして使う

sbtで.projectを作成したので、それを読み込む。File -> Import...Existing Projects into Workspace"Browse..." からws/sampleディレクトリを選択。結果的にこんな感じにAppEngineのライブラリが読み込まれた状態でプロジェクトが出来る。

ルーティン

依存ライブラリが増えた場合はbuild.sbtを修正し、reload -> updateを行う。 その後、eclipse create-srcを実行し.projectを作成。 Eclipseに反映するために、更新(F5)を行う。

この環境はsbtとEclipseの共存なので、好きな方を使えばいい。 テストの実行をリアルタイムに行いたいなら、sbtで "~test" しておけばいいし、トレース実行したいならいつものようにEclipseを使えばいい。

課題

ひとつだけ問題があって、Eclipseでテストは実行できるんだけど、sbtでコンパイルすると次のエラーが発生してテストに失敗する。
NullPointerException: No API environment is registered for this thread. (DatastoreApiHelper.java:118)
これはAppEngine絡みの問題なので、AppEngineを使わない人は出会わないだろうし、設定次第で解決できそうな気もする。

今回作ったプロジェクトはEclipseのプラグインを導入してない。導入した所で.projectファイル作成時に設定が上書きされ、消えてしまう。 ■ eed3si9n/sbt-appengine - GitHub

https://github.com/eed3si9n/sbt-appenginesbt-appengineプラグインもあるんだけど、うまく動かなかったので放置してる。

実は…

このやり方、pomuさんに教えてもらったんだけどね。 [blackbirdpie id="117144635427663872"]

· 4 min read

いつの間にかsbtのバージョンが0.9.1とかなっていたので、慌てて持ってきました! 昨日、sbtバージョンアップしないなぁ…とか思ってたら、ここにあった。 ■ harrah/xsbt - GitHub

https://github.com/harrah/xsbt

sbtはbrewでインストールしてたからbrew管理したかったけど、今の状況を見るとbrew管理しない方がよさそう。

ダウンロード

まずは、ファイルをダウンロードして、展開。 harrah-xsbt-v0.9.1-0-g3ce0e5d.zipというファイル名でした。
unzip harrah-xsbt-v0.9.1-0-g3ce0e5d.zip

ビルド…の前の余談

ビルド時にScala 2.9.0-SNAPSHOTの取得に時間がかかっていて、反応がなかったから2.9.0は消した。
cd harrah-xsbt-3ce0e5d vi project/build/XSbt.scala
lazy val precompiled29 = precompiledSub("2.9.0-SNAPSHOT")
この一行をコメントアウトする。でも、今はこんなことしなくても大丈夫っぽい。

それと、compileをやったらPermGenがOutOfMemoryになった。 そんなわけで、sbtの実行スクリプトは下記にように修正。

java -Xmx1024M -XX:MaxPermSize=512m -jar /usr/local/Cellar/sbt/0.7.4/libexec/sbt-launch-0.7.4.jar "$@"

-Xmx1024M -XX:MaxPermSize=512mを追加して、潤沢にしました。

実際はこれだけあれば足りるらしい。 以下のビルドもこの助言のとおりにやっただけだったりする🙄

ビルド

本題のビルド。
sbt set build.scala.versions 2.8.1 reload update proguard publish-local
updateでエラーが出たので、懲りずに何回もやったらなんとか通った。応答遅かったりと、ネットワークの問題かな? proguardも何回かやったけど、エラーは消えなかった。これは難読化とか最適化とか、本体に直接関係ないのでエラー出たままpublish-localした。

jarを差し替える

targetディレクトリにsbt-launch-0.9.1.jarが出来ているので、これを既存のsbtと差し替えて完了。

注意

0.7.4のときと比べて、かなりコマンドが増えてる!? まず、currentコマンドがなくなってて、自分が何者かわからない。 どっかのディレクトリでsbtを実行すると、いきなり "project" と "target" ディレクトリが出来るので注意。

· 5 min read
前回の投稿でIDEAとsbt-appengineが連携してくれたのは嬉しいけど、ソースを修正するたびにappserverの再起動は面倒!! 出来ることなら、IDEAでコーディング→ブラウザ確認→コーディング→...と繰り返したい。

こちらも実現できたので、方法を紹介。 やったことはこれだけ。

  • JRebelでクラスリローディング
  • クラスファイルの出力先をwebapp配下にする
  • sbtでソースコード監視

環境を簡単に書いておくと、IDEA+sbt(appengine plugin)という組み合わせ。 MyProjectがあって、その下にSubProject1, SubProject2がある構成。このMyProjectとかSubProjectはsbtの管理下にある状態。

まずはJRebelの導入から。 JRebel自体は有償だけど、Scala開発者にはライセンスを提供してくれてるのでこれを活用。 ■ ZeroTurnaround

http://sales.zeroturnaround.com/jrebel.jarを適当な場所に置く。ライセンスファイルもjarと同じところに置いておく。

JRebelでクラスリローディング

クラスリローディング対象とするディレクトリを指定するために、rebel.xmlを作成する。 MyProject/src/test/resources/rebel.xml
<?xml version="1.0"?>
<application>
<classpath>
<dir name="/Users/ken/workspace/MyProject/SubProject1/target/scala_2.8.1/classes" />
<dir name="/Users/ken/workspace/MyProject/SubProject2/target/scala_2.8.1/classes" />
</classpath>
</application>

続いて、sbtでJRebelを有効にする。 sbt-appengine-pluginではJREBEL_JAR_PATHを指定するだけでJRebelが有効になるはずなんだけど、IDEAのsbtコンソールでは環境変数を見てくれないらしいので、直接指定します。 MyProject/project/build/Project.scala

override def scanDirectories = Nil
override val devAppserverJvmOptions = List("-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,address=2011,suspend=y") ++ List("-noverify", "-javaagent:/Users/ken/dev/jrebel/jrebel.jar") ++ super.devAppserverJvmOptions

JRebelに関係するのは

List("-noverify", "-javaagent:/Users/ken/dev/jrebel/jrebel.jar")

の部分。 ちなみに、XdebugとかはIDEAで接続するための記述。

クラスファイルの出力先をwebapp配下にする

JRebelの設定も終わったので、あとはIDEAからsbtを実行すればいいんだけど、sbtの出力先がappengineの出力先(webapp)とは異なっているためsbtの "~ compile" で監視をしても意味が無い。

そこで、SubProjectの出力先をwebapp配下にします。具体的には、MyProject/SubProject1/target/scala_2.8.1/classesを削除して、MyProject/target/scala_2.8.1/webapp/WEB-INF/classesにシンボリックリンクを張る。 手動でシンボリックリンクを張ればいいんだけど、sbt cleanを実行すると再度やり直さなければならないので、symlinkアクションを作った。 MyProject/project/build/Project.scala

import java.lang.Runtime
lazy val symlinkInstance = new Symlink
lazy val symlink = symlinkAction
def symlinkAction = task { args => task { symlinkInstance(args); None } }
class Symlink() extends Runnable {
def run() = {
def exec(command:String) = Runtime.getRuntime.exec(command)
val subs = Set("SubProject1", "SubProject2")
val webapp = outputPath / "webapp" / "WEB-INF" / "classes"

log.info("Creating directory %s".format(webapp))
exec("mkdir -p %s".format(webapp))

subs.foreach { sub =>
log.info("Processing for %s.".format(sub))
val path = "%s/%s".format(sub, mainCompilePath)
val command = "ln -s ../../../%s %s".format(webapp, path)

log.info("Removing directory %s".format(path))
exec("rm -fr %s".format(path))

log.info("Creating symlink %s -> %s".format(path, webapp))
exec(command)
log.info("")
}
None
}

def apply(args:Seq[String]):Option[String] = {
new Thread(this).start()
None
}

}

コード中の val subs = Set("SubProject1", "SubProject2")" を各自の環境に合わせてください。

sbt reload後に "symlink" アクションが追加されているので、実行してパスを確認して下さい。サブプロジェクトのclassesがシンボリックリンクになっているはず。

使い方

  1. sbtで "symlink" を実行。
  2. IDEAでデバッガ実行(=sbtも起動。前回の投稿参照)
  3. sbtで "~ compile" を実行

簡単に仕組みを説明。 symlinkを実行することによって、appserverの管理下にクラスファイルを出力するようになります。単にシンボリックリンクを張るだけなので初回だけ。sbt cleanしたときは再度実行します。 続いて、IDEAでデバッガを起動し、sbtの "~ compile" を実行してソースファイルを監視します。ソースコードに修正があった場合はsbtの監視によってコンパイルされ、クラスファイルが生成されます(生成先はsbt symlinkによってappsever管理下になっている)。 ブラウザからアクセスすると、JRebelによってクラスの再読込が行われ、sbtには "JRebel: Reloading class 'package.path.to.ClassName'." と出力されます。

これで、IDEAからsbtを起動し、ブラウザで確認しつつコードを書いていくことが出来る♪

· 3 min read

IDEAとsbtを連携してデバッグしたいと思っていたところ@pomu0325さんが解決してくれた。 だけど、appengineの起動はsbtコンソールにdev-appserver-startと入力しなくてはならず、面倒。 どうせなら、IDEAのデバッグ時に一緒にappserverも起動して欲しい。 これを解決する方法がわかったので、紹介。

まずはpomu0325さんのところにも記述があるように "Before launch" の "Run SBT Action" に "dev-appserver-start" を指定する。 このままIDEAから実行してもappserverは起動するんだけど、dev-appserver-startを実行直後にIDEAが接続に行くらしく、コネクションが張れずにエラーとなってしまう。 ということは、コネクションを張るタイミングを遅らせてあげればいいはず。

MyProject/project/build/Project.scalaに以下を追記。

override def devAppserverStartTask(args:Seq[String]) = task {
val status = devAppserverInstance(args)
Thread.sleep(5000)
status
}

これによってdev-appserver-startを実行後、5秒(5000ms)スリープする。 この5秒というのは各自のマシンスペックと相談して、適当に変更してください。

あとはsbtでreload後、IDEAでデバッグするだけ。 appserver起動後にIDEAがコネクションを張りに行くはずです。

余談だけど、こんな記述をしておくとちょっと楽できるかも?

lazy val start = devAppserverStartAction
lazy val stop = devAppserverStop

sbtでdev-appserver-startのエイリアスとしてstartを定義してます。同様にstopも。 appserverの起動はIDEAから可能だけど、sbtのappserverを停止するときにstopが役立つかも?

· 5 min read

IDEAとsbtで開発するための手順。 今回はsbtでベースを作り、IDEAで開発環境を構築する方法。

■ An integrated SBT + IDEA Scala Development Setup ← Decodified

http://www.decodified.com/scala/2010/10/12/an-integrated-sbt-and-idea-scala-dev-setup.html参考にしたサイトはこちら。

使ったことはないが、sbtの定義ファイルからIDEAのプロジェクトファイルを作ってくれるsbt pluginもあるらしい。 ■ sbt-idea 0.1.0 - implicit.ly

http://implicit.ly/sbt-idea-010

以下が本題の手順。

前提

プロジェクトとして "Hello"を、サブプロジェクトととして "World" を作成することにする。 (HelloProject…ハロプロ?…まぁ、いっか)

最終的にはIDEAのプロジェクトとして "Hello" を、モジュールとして "World" が出来ることになる。

sbtの準備

sbtのインストールはご自由に。 ■ simple-build-tool - Project Hosting on Google Codehttp://code.google.com/p/simple-build-tool/

MacBookにはhomebrewの環境を作ってあるので、うちはこれでインストール完了。

brew install sbt

実際に利用するjarファイルはここにインストールされる。 /usr/local/Cellar/sbt/0.7.4/libexec/sbt-launch-0.7.4.jar

sbtによるHelloプロジェクト作成

まずはHelloプロジェクトを作成。
$ cd $WORKSPACE $ mkdir hello $ cd hello $ sbt[object Object]
exitでsbtから抜ける。

続いて、Worldモジュールを作成。

$ mkdir world $ cd world/ $ sbt Project does not exist, create new project? (y/N/s) y Name: World Organization: Hello Version [1.0]: Scala version [2.7.7]: 2.8.1 sbt version [0.7.4]:

exitでsbtから抜ける。

これで、sbtを利用したHelloプロジェクトとWorldモジュールの作成を完了。

IDEAプロジェクトの構築

File - New Project...からプロジェクトの作成を開始する。このまま次へ進む。"Name" は気にせず "Project files location" を選択する。選択するとNameも変更されます。 "Create module" のチェックは外しておく。

プロジェクトの作成は完了したので、続いてモジュールの作成に移る。

真ん中のペインの上にある "+" を押し、モジュールを追加する。次へ進む。モジュールを選択し、次へ進む。"Do not create source directory" を選択し、次へ進む。何も選択せず、次へ進む。"Source Folders", "Test Source Folders", "Excluded Folders" を設定。隣の "Paths" タブを選択し "Output path" と "Test output path" を設定。

sbtコンソールを使う

sbtプラグインを入れておく。sbt-launch.jarのパスを設定しておく。下の "SBT Console" を押すとコンソールが出てくるので、緑色の再生ボタンを押す。 これでsbtが起動したら完了。

トラブルシューティング

最後のsbt起動の際に、sbtの設定を完了しておかないとIDEAが固まる現象が発生した。固まってしまったら、Terminalからsbtのプロセスをkillすることで解決する。

実際に活用するのはこれからなので、使いやすさなどは不明。 IntelliJ IDEAとsbtは使いやすいという噂を聞いたことはあるが、実際に設定手順をまとめてるサイトがなかったので、簡単に書いてみた。