既に存在する多くのロジックをコピペせずに、サブプロジェクトから既存のロジックをimportしてサブプロジェクトもjarとして生成したいと思ったので試した。
プロジェクト1つの状態でsbt-assemblyを使ってjar生成
プロジェクト1つの時代の元のディレクトリ構成(雰囲気)
app/src/
/project/
/target/
/build.sbt
元のbuild.sbt
lazy val root = (project in file(".")).
settings(
name := "project1",
version := "1.0",
scalaVersion := "2.12.8",
libraryDependencies ++= dervy,
testTasks in Test := {},
test in assembly := {}
)
lazy val testTasks = taskKey[Unit]("test tasks.")
lazy val dervy = {
Seq(
使うライブラリ達
)
}
parallelExecution in Test := false
assemblyMergeStrategy in assembly := {
case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
case PathList("org", "slf4j", xs @ _*) => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".properties" => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".xml" => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".types" => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".class" => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".txt" => MergeStrategy.first
case "application.conf" => MergeStrategy.concat
case "unwanted.txt" => MergeStrategy.discard
case "BUILD" => MergeStrategy.discard
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
case x =>
val oldStrategy = (assemblyMergeStrategy in assembly).value
oldStrategy(x)
}
この状態でsbt assembly
(addSbtPluginは設定済みの状態)を実行するとapp/target/scala-2.12/project1-assembly-1.0.jar
が生成される。
これまでがプロジェクト1つの場合
マルチプロジェクトでsbt-assemblyを使ってそれぞれのjar生成
マルチプロジェクトのディレクトリ構成(雰囲気)
app/src/
/project/
/target/
/sub-project/ <- 後にbuild.sbtにプロジェクト追加すると生成されるディレクトリ
/build.sbt
サブプロジェクトを追加したbuild.sbt
変更点としてはassemblySettingsをまとめてそれぞれのプロジェクトに設定しているのと、subProjectを作成している点。
subProjectにはdependsOnでproject1のクラス等をimport出来るようにしている。
※各プロジェクトの設定はcommonSettingsを設定した方が良いがやってない。
マルチプロジェクト・ビルド 共通のセッティング
lazy val root = (project in file(".")).
settings(
name := "project1",
version := "1.0",
scalaVersion := "2.12.8",
libraryDependencies ++= dervy,
testTasks in Test := {},
assemblySettings, // 追加
test in assembly := {}
)
lazy val subProject = (project in file("sub-project")).
dependsOn(root).
settings(
name := "sub-project",
version := "1.0",
scalaVersion := "2.12.8",
libraryDependencies ++= dervy,
testTasks in Test := {},
assemblySettings, // subProjectでも設定
test in assembly := {}
)
lazy val testTasks = taskKey[Unit]("test tasks.")
lazy val dervy = {
Seq(
使うライブラリ達
)
}
parallelExecution in Test := false
// 設定をassemblySettingsにまとめる
lazy val assemblySettings = Seq(
assemblyMergeStrategy in assembly := {
case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
case PathList("org", "slf4j", xs @ _*) => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".properties" => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".xml" => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".types" => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".class" => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".txt" => MergeStrategy.first
case "application.conf" => MergeStrategy.concat
case "unwanted.txt" => MergeStrategy.discard
case "BUILD" => MergeStrategy.discard
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
case x =>
val oldStrategy = (assemblyMergeStrategy in assembly).value
oldStrategy(x)
}
)
このようなbuild.sbtになっている状態でsbt
を起動してprojects
コマンドと入力すると、root
とsubProject
の2つが表示されるようになる
subProjectに切り替える場合project subProject
と入力すると切り替わる
この時点でsub-project
ディレクトリが生成されていると思うのでsrc/main/scala/com/github/TakashiOshikawa/SubMain.scala
を作成して元々存在するロジックをsubProjectから利用してみる。
// ※パッケージ名は好きなように
package com.github.TakashiOshikawa
// ここでproject1側のクラスをimport出来ることを確認
import com.github.TakashiOshikawa.services.SomeService
object SubProjectMain {
def main(args: Array[String]) = {
println("sub project main !!")
println(SomeService.run(1))
}
}
これでsbt subProject/compile
やsbt subProject/run
で実行できることを確認したらsbt-assemblyでjar生成していく
project1のコマンド sbt assembly
sub projectのコマンド sbt subProject/assembly
それぞれのjarは以下のように生成された
app/target/scala-2.12/project1-assembly-1.0.jar
app/sub-project/target/scala-2.12/sub-project-assembly-1.0.jar
まとめ
マルチプロジェクトの記事はそこそこあるが、サブプロジェクトのjarをsbt-assemblyで生成するのはあまり見かけなかったので少し手こずった。
そもそもプロジェクトごとにjar生成なんて殆どやることはなくて、単にプロジェクト分割して各レイヤーの依存方向を強制するために使うのが普通なのかどうなのか…
参照
https://github.com/sbt/sbt-assembly
https://www.scala-sbt.org/1.x/docs/ja/Multi-Project.html#%E5%85%B1%E9%80%9A%E3%81%AE%E3%82%BB%E3%83%83%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0
https://www.qoosky.io/techs/1ec18db8bc
https://pbassiner.github.io/blog/defining_multi-project_builds_with_sbt.html
https://stackoverflow.com/questions/37588407/how-to-make-multi-project-fat-jar-with-sbt-assembly