Skinny Frameworkでstandaloneなjarを作る


*2014/01/20追記*

#### version 0.9.26利用
https://github.com/skinny-framework/skinny-framework/releases
skinny-blank-app.zipをダウンロード、解凍

```zsh
$ cd skinny-blank-app
$ ./skinny package:standalone
$ java -jar ./standalone-build/target/scala-2.10/skinny-standalone-app-assembly-0.1.0-SNAPSHOT.jar
```

以上です

0.9.25以降のバージョンで、以下の手順は必要ありません。

[Skinny Framework](http://skinny-framework.org/)でjettyを組み込んだstandaloneなjarを作ってみる
scalatraの[Standalone deployment](http://scalatra.org/2.2/guides/deployment/standalone.html)を真似すればいいはず
*追記あり*

#### skinny-blank-appを取得

https://github.com/skinny-framework/skinny-framework/releases

skinny-blank-app.zipをダウンロード、解凍
（ここではversion 0.9.24を利用）

#### jettyの設定

まずはjettyを起動するためのLauncherスクリプトを先ほどの[Standalone deployment](http://scalatra.org/2.2/guides/deployment/standalone.html)からコピペして、src/main/scala/JettyLauncher.scalaに保存

https://github.com/ise/skinny-blank-app-standalone/commit/f98c563c544bd8d42e1fe864133d9b1ded325ddd#diff-13139407832210e6a7d93d956d1318fe

project/Build.scalaにstandaloneで動かすために必要なdependencyを追加
（あとjettyが9系だとエラーが出るので8系に下げる）

```scala
 -  val jettyVersion = "9.0.7.v20131107"
 +  //val jettyVersion = "9.0.7.v20131107"
 +  val jettyVersion = "8.1.14.v20131031"

   val _resolovers = Seq(
      "sonatype releases"  at "http://oss.sonatype.org/content/repositories/releases"
 @@ -24,7 +25,10 @@ object SkinnyAppBuild extends Build {
      "org.skinny-framework" %% "skinny-task"        % skinnyVersion,
      "com.h2database"       %  "h2"                 % "1.3.174", // your JDBC driver
      "ch.qos.logback"       %  "logback-classic"    % "1.0.13",
 -    "org.skinny-framework" %% "skinny-test"        % skinnyVersion         % "test"
 +    "org.skinny-framework" %% "skinny-test"        % skinnyVersion         % "test",
 +    "org.eclipse.jetty"    %  "jetty-webapp"       % jettyVersion          % "compile",
 +    "org.eclipse.jetty"    %  "jetty-servlet"      % jettyVersion          % "compile",
 +    "org.eclipse.jetty"    %  "jetty-server"       % jettyVersion          % "compile"
    )
```

#### sbt-assemblyを導入

build.sbtを修正

```scala
import AssemblyKeys._

assemblySettings

mainClass in assembly := Some("com.example.JettyLauncher")

initialCommands := """
import _root_.controller._, model._
import org.joda.time._
import scalikejdbc._, SQLInterpolation._, config._
DBsWithEnv("development").setupAll()
"""
```

project/plugins.sbtに追記

```scala
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.10.2")
```

#### ビルド

skinnyシェルスクリプトを参考に、css/jsのプリコンパイル後、assemblyを実行する
skinny packageやskinny publishを実行したときに行われる処理は以下の通り

```sh
rm -rf build
mkdir build
cp -pr src build/src
cp -pr build.sbt build/build.sbt
sbt "task/run assets:precompile" build/package # or sbt "task/run assets:precompile" build/publish
```

毎回buildディレクトリを新規作成し、そこ以下でプリコンパイル、ビルドを行っているので、
assemblyも同様にやってやればよいはず。

```sh
$ rm -r build;mkdir build;cp -pr src build/src;cp -pr build.sbt build/build.sbt
$ sbt "task/run assets:precompile" build/assembly
```

これで、build/target/scala-2.10/skinny-blank-app-assembly-0.0.1-SNAPSHOT.jarができた
jarを実行

```sh
$ java -jar build/target/scala-2.10/skinny-blank-app-assembly-0.0.1-SNAPSHOT.jar
```

8080ポートにアクセスするとskinnyのサンプルアプリが表示されるはず

まとめrepository
- https://github.com/ise/skinny-blank-app-standalone
- https://github.com/ise/skinny-blank-app-standalone/commit/f98c563c544bd8d42e1fe864133d9b1ded325ddd

#### 参考

- https://gist.github.com/seratch/7382298#file-getting_started_ja-md
- http://m0t0k1ch1st0ry.com/blog/2013/10/14/scalatra-1/
- http://takuya71.hatenablog.com/entry/2013/06/22/180808

#### jettyのバージョンについて

9.0.7.v20131107だと以下のようなエラーでビルドに失敗したため、8.1.14.v20131031に下げたけど、これでよかったのだろうか

```
[info] RootControllerSpec:
java.lang.NoSuchMethodError: org.eclipse.jetty.server.Connector.getHost()Ljava/lang/String;
	at org.scalatra.test.EmbeddedJettyContainer$class.baseUrl(EmbeddedJettyContainer.scala:40)
	at controller.RootControllerSpec.baseUrl(RootControllerSpec.scala:6)
	at org.scalatra.test.HttpComponentsClient$class.submit(HttpComponentsClient.scala:63)
	at controller.RootControllerSpec.submit(RootControllerSpec.scala:6)
	at org.scalatra.test.Client$class.get(Client.scala:44)
	at controller.RootControllerSpec.get(RootControllerSpec.scala:6)
	at controller.RootControllerSpec$$anonfun$1.apply$mcV$sp(RootControllerSpec.scala:11)
	at controller.RootControllerSpec$$anonfun$1.apply(RootControllerSpec.scala:11)
	at controller.RootControllerSpec$$anonfun$1.apply(RootControllerSpec.scala:11)
	at org.scalatest.FlatSpec$$anon$1.apply(FlatSpec.scala:2977)
	at org.scalatest.Suite$class.withFixture(Suite.scala:1974)
	at controller.RootControllerSpec.withFixture(RootControllerSpec.scala:6)
	at org.scalatest.FlatSpec$class.invokeWithFixture$1(FlatSpec.scala:2974)
	at org.scalatest.FlatSpec$$anonfun$runTest$1.apply(FlatSpec.scala:2983)
	at org.scalatest.FlatSpec$$anonfun$runTest$1.apply(FlatSpec.scala:2983)
	at org.scalatest.SuperEngine.runTestImpl(Engine.scala:198)
	at org.scalatest.FlatSpec$class.runTest(FlatSpec.scala:2983)
	at controller.RootControllerSpec.runTest(RootControllerSpec.scala:6)
	at org.scalatest.FlatSpec$$anonfun$runTests$1.apply(FlatSpec.scala:3045)
	at org.scalatest.FlatSpec$$anonfun$runTests$1.apply(FlatSpec.scala:3045)
	at org.scalatest.SuperEngine$$anonfun$org$scalatest$SuperEngine$$runTestsInBranch$1.apply(Engine.scala:260)
	at org.scalatest.SuperEngine$$anonfun$org$scalatest$SuperEngine$$runTestsInBranch$1.apply(Engine.scala:249)
	at scala.collection.immutable.List.foreach(List.scala:318)
	at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:249)
	at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:326)
	at org.scalatest.FlatSpec$class.runTests(FlatSpec.scala:3045)
	at controller.RootControllerSpec.runTests(RootControllerSpec.scala:6)
	at org.scalatest.Suite$class.run(Suite.scala:2303)
	at controller.RootControllerSpec.org$scalatest$FlatSpec$$super$run(RootControllerSpec.scala:6)
	at org.scalatest.FlatSpec$$anonfun$run$1.apply(FlatSpec.scala:3092)
	at org.scalatest.FlatSpec$$anonfun$run$1.apply(FlatSpec.scala:3092)
	at org.scalatest.SuperEngine.runImpl(Engine.scala:362)
	at org.scalatest.FlatSpec$class.run(FlatSpec.scala:3092)
	at controller.RootControllerSpec.org$scalatest$BeforeAndAfterAll$$super$run(RootControllerSpec.scala:6)
	at org.scalatest.BeforeAndAfterAll$class.run(BeforeAndAfterAll.scala:213)
	at controller.RootControllerSpec.run(RootControllerSpec.scala:6)
	at org.scalatest.tools.ScalaTestFramework$ScalaTestRunner.run(ScalaTestFramework.scala:214)
	at sbt.RunnerWrapper$1.runRunner2(FrameworkWrapper.java:220)
	at sbt.RunnerWrapper$1.execute(FrameworkWrapper.java:233)
	at sbt.TestRunner.runTest$1(TestFramework.scala:84)
	at sbt.TestRunner.run(TestFramework.scala:94)
	at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:224)
	at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:224)
	at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:212)
	at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:224)
	at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:224)
	at sbt.TestFunction.apply(TestFramework.scala:229)
	at sbt.Tests$$anonfun$7.apply(Tests.scala:196)
	at sbt.Tests$$anonfun$7.apply(Tests.scala:196)
	at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
	at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
	at sbt.std.Transform$$anon$4.work(System.scala:64)
	at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
	at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
	at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
	at sbt.Execute.work(Execute.scala:244)
	at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
	at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
	at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
	at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
	at java.util.concurrent.FutureTask.run(FutureTask.java:166)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
	at java.util.concurrent.FutureTask.run(FutureTask.java:166)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:722)
[error] Could not run test controller.RootControllerSpec: java.lang.NoSuchMethodError: org.eclipse.jetty.server.Connector.getHost()Ljava/lang/String;
[error] Error: Total 0, Failed 0, Errors 0, Passed 0
[error] Error during tests:
[error] 	controller.RootControllerSpec
[error] (build/test:test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 5 s, completed 2014/01/13 11:31:35
```

#### 追記
*コメントで教えてもらった通り、build.sbtを修正すれば動いた*
https://github.com/ise/skinny-blank-app-standalone/commit/b647cec2fd95011a438e176d3d18b94fcc11ee81

そして、skinnyの0.9.25ではシェルスクリプトの一部コメントアウトを解除するだけで、
standaloneで動作するパッケージが作成できるようになるとのこと。
*seratchさんすごすぎ*