我正在尝试使用sbt-assembly将scala项目转换为可部署的胖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文档:
如果多个文件共享相同的相对路径(例如,名为的资源) application.conf在多个依赖JAR中),默认策略是 验证所有候选人是否具有相同的内容和错误 除此以外。可以使用每个路径配置此行为 以下内置策略之一或编写自定义策略:
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
有人可以指出我在这里做错了吗?
由于
答案 0 :(得分:11)
对于当前版本0.11.2(2014-03-25),定义合并策略的方式不同。
记录在案here,相关部分是:
注意: 程序集中的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)
}
}
这也可能适用于早期版本,我不确切知道它何时发生变化。
答案 1 :(得分:8)
我刚刚设置了一个需要重新连接一些mergeStrategies的sbt项目,并且发现答案有点过时,让我添加我的工作代码版本(截至4-7-2015)
装配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)
}
答案 2 :(得分:7)
我认为MergeStrategy.first
应该是M
,mergeStrategy in assembly := MergeStrategy.first
。
答案 3 :(得分:3)
对于新的sbt版本(sbt-version:0.13.11),我收到了slf4j的错误;暂时采取了简单的方法:请在这里查看答案Scala SBT Assembly cannot merge due to de-duplication error in StaticLoggerBinder.class,其中提到了sbt-dependency-graph工具,手动执行此操作非常酷
assemblyMergeStrategy in assembly <<= (assemblyMergeStrategy in assembly) {
(old) => {
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
case x => MergeStrategy.first
}
}
答案 4 :(得分:2)
这是合并大多数常见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}
答案 5 :(得分:0)
快速更新:不建议使用mergeStrategy。使用assemblyMergeStrategy。除此之外,早期的反应仍然很可靠
答案 6 :(得分:0)
在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
}