web-dev-qa-db-ja.com

sbt-assemblyを使用したアセンブリーマージ戦略の問題

scalaプロジェクトを sbt-Assembly を使用してデプロイ可能なファットjarに変換しようとしています。sbtでアセンブリタスクを実行すると、次のエラーが発生します。

Merging 'org/Apache/commons/logging/impl/SimpleLog.class' with strategy 'deduplicate'
    :Assembly: deduplicate: different file contents found in the following:
    [error] /Users/home/.ivy2/cache/commons-logging/commons-logging/jars/commons-logging-1.1.1.jar:org/Apache/commons/logging/impl/SimpleLog.class
    [error] /Users/home/.ivy2/cache/org.slf4j/jcl-over-slf4j/jars/jcl-over-slf4j-1.6.4.jar:org/Apache/commons/logging/impl/SimpleLog.class

Sbt-Assemblyのドキュメントから:

複数のファイルが同じ相対パス(たとえば、複数の依存関係JAR内のapplication.confという名前のリソース)を共有している場合、デフォルトの戦略は、すべての候補が同じ内容であり、そうでない場合はエラーになることを確認することです。この動作は、次の組み込み戦略のいずれかを使用するか、カスタム戦略を作成して、パスごとに構成できます。

  • MergeStrategy.deduplicateは上記のデフォルトです
  • MergeStrategy.first一致するファイルの最初をクラスパス順に選択します
  • MergeStrategy.last最後のものを選びます
  • MergeStrategy.singleOrError競合時にエラーメッセージが表示されて一時停止します
  • MergeStrategy.concat一致するすべてのファイルを単純に連結し、結果を含めます
  • MergeStrategy.filterDistinctLinesも連結しますが、途中で重複を除外します
  • MergeStrategy.renameは、jarファイルに由来するファイルの名前を変更します
  • MergeStrategy.discard一致するファイルを単に破棄する

これで、build.sbtを次のようにセットアップしました。

import sbt._
import Keys._
import sbtassembly.Plugin._
import AssemblyKeys._
name := "my-project"
version := "0.1"
scalaVersion := "2.9.2"
crossScalaVersions := Seq("2.9.1","2.9.2")

//assemblySettings
seq(assemblySettings: _*)

resolvers ++= Seq(
    "Typesafe Releases Repository" at "http://repo.typesafe.com/typesafe/releases/",
    "Typesafe Snapshots Repository" at "http://repo.typesafe.com/typesafe/snapshots/",
    "Sonatype Repository" at "http://oss.sonatype.org/content/repositories/releases/"
)

libraryDependencies ++= Seq(
    "org.scalatest" %% "scalatest" % "1.6.1" % "test",
    "org.clapper" %% "grizzled-slf4j" % "0.6.10",
    "org.scalaz" % "scalaz-core_2.9.2" % "7.0.0-M7",
    "net.databinder.dispatch" %% "dispatch-core" % "0.9.5"
)

scalacOptions += "-deprecation"
mainClass in Assembly := Some("com.my.main.class")
test in Assembly := {}
mergeStrategy in Assembly := mergeStrategy.first

Build.sbtの最後の行には、次のようになっています。

mergeStrategy in Assembly := mergeStrategy.first

SBTを実行すると、次のエラーが発生します。

error: value first is not a member of sbt.SettingKey[String => sbtassembly.Plugin.MergeStrategy]
    mergeStrategy in Assembly := mergeStrategy.first

誰かが私がここで間違っているかもしれないことを指摘できますか?

ありがとう

26
sc_ray

MergeStrategy.first大文字のMなので、mergeStrategy in Assembly := MergeStrategy.first

6
user500592

現在のバージョン0.11.2(2014-03-25)については、マージ戦略の定義方法が異なります。

これは文書化されています ここ 、関連する部分は次のとおりです:

注:AssemblyのmergeStrategyは関数を想定しているため、実行できません

mergeStrategy in Assembly := MergeStrategy.first

新しい方法は(同じソースからコピー)です。

mergeStrategy in Assembly <<= (mergeStrategy in Assembly) { (old) =>
  {
    case PathList("javax", "servlet", xs @ _*)         => MergeStrategy.first
    case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
    case "application.conf" => MergeStrategy.concat
    case "unwanted.txt"     => MergeStrategy.discard
    case x => old(x)
  }
}

これは以前のバージョンにも当てはまる可能性があります。いつ変更されたかは正確にはわかりません。

13
Beryllium

私はいくつかのmergeStrategiesを再配線する必要がある小さなsbtプロジェクトをセットアップしました、そして答えが少し古くなっているのを発見しました、バージョン用の私の動作するコードを追加させてください(2015年4月7日現在)

  • sbt 0.13.8
  • scala 2.11.6
  • アセンブリ0.13.0

    mergeStrategy in Assembly := {
      case x if x.startsWith("META-INF") => MergeStrategy.discard // Bumf
      case x if x.endsWith(".html") => MergeStrategy.discard // More bumf
      case x if x.contains("slf4j-api") => MergeStrategy.last
      case x if x.contains("org/cyberneko/html") => MergeStrategy.first
      case PathList("com", "esotericsoftware", xs@_ *) => MergeStrategy.last // For Log$Logger.class
      case x =>
         val oldStrategy = (mergeStrategy in Assembly).value
         oldStrategy(x)
    }
    
8
mrArias

新しいsbtバージョン(sbt-version:0.13.11)の場合、slf4jのエラーが発生しました。とりあえず、簡単な方法で取り除きます。ここでも回答を確認してください StaticLoggerBinder.classの重複排除エラーのため、Scala SBTアセンブリをマージできません ここで sbt-dependency-graph =手動でこれを行うのはかなりクールなツールが言及されています

assemblyMergeStrategy in Assembly <<= (assemblyMergeStrategy in Assembly) {
  (old) => {
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard
    case x => MergeStrategy.first
  }
}
4
Alex Punnen

これは、ほとんどの一般的なJava/scalaプロジェクトをマージする適切な方法です。 META-INFとクラスを処理します。

また、META-INFでのサービス登録も処理されます。

assemblyMergeStrategy in Assembly := {
case x if Assembly.isConfigFile(x) =>
  MergeStrategy.concat
case PathList(ps @ _*) if Assembly.isReadme(ps.last) || Assembly.isLicenseFile(ps.last) =>
  MergeStrategy.rename
case PathList("META-INF", xs @ _*) =>
  (xs map {_.toLowerCase}) match {
    case ("manifest.mf" :: Nil) | ("index.list" :: Nil) | ("dependencies" :: Nil) =>
      MergeStrategy.discard
    case ps @ (x :: xs) if ps.last.endsWith(".sf") || ps.last.endsWith(".dsa") =>
      MergeStrategy.discard
    case "plexus" :: xs =>
      MergeStrategy.discard
    case "services" :: xs =>
      MergeStrategy.filterDistinctLines
    case ("spring.schemas" :: Nil) | ("spring.handlers" :: Nil) =>
      MergeStrategy.filterDistinctLines
    case _ => MergeStrategy.first
  }
case _ => MergeStrategy.first}
2
linehrr

クイックアップデート:mergeStrategyは非推奨になりました。 assemblyMergeStrategyを使用します。それとは別に、以前の反応はまだしっかりしています

1
Jake

Build.sbtに以下を追加して、kafkaをソースまたは宛先として追加します

 assemblyMergeStrategy in Assembly := {
 case PathList("META-INF", xs @ _*) => MergeStrategy.discard
 //To add Kafka as source
 case "META-INF/services/org.Apache.spark.sql.sources.DataSourceRegister" => 
 MergeStrategy.concat
 case x => MergeStrategy.first
 }
0
Sushruth