【发布时间】:2014-08-13 08:12:39
【问题描述】:
我们有一种情况,其中两个依赖项具有完全相同的类(因为其中一个依赖项复制了它并包含在它们自己的源中)。
这导致sbt assembly 的重复数据删除检查失败。
如何从特定 jar 中排除一个类?
【问题讨论】:
标签: sbt sbt-assembly
我们有一种情况,其中两个依赖项具有完全相同的类(因为其中一个依赖项复制了它并包含在它们自己的源中)。
这导致sbt assembly 的重复数据删除检查失败。
如何从特定 jar 中排除一个类?
【问题讨论】:
标签: sbt sbt-assembly
您需要一个mergeStrategy,它将获取其中一个文件。
mergeStrategy in assembly := {
case PathList("path", "to", "your", "DuplicatedClass.class") => MergeStrategy.first
case x => (mergeStrategy in assembly).value(x)
}
如果你想根据它来自的 JAR 来处理文件,我认为你不能使用程序集插件定义的合并策略。你能做什么,你可以定义自己的策略。
不过,我会颠倒你的情况。我认为问题应该是“如何包含来自特定 JAR 的类?”。原因是同一类的 JAR 可以有两个以上,最后只能包含一个。
您可以使用AssemblyUtils.sourceOfFileForMerge 来判断文件的来源。
project/IncludeFromJar.scalaimport sbtassembly._
import java.io.File
import sbtassembly.Plugin.MergeStrategy
class IncludeFromJar(val jarName: String) extends MergeStrategy {
val name = "includeFromJar"
def apply(args: (File, String, Seq[File])): Either[String, Seq[(File, String)]] = {
val (tmp, path, files) = args
val includedFiles = files.flatMap { f =>
val (source, _, _, isFromJar) = sbtassembly.AssemblyUtils.sourceOfFileForMerge(tmp, f)
if(isFromJar && source.getName == jarName) Some(f -> path) else None
}
Right(includedFiles)
}
}
build.sbtmergeStrategy in assembly := {
case PathList("path", "to", "your", "DuplicatedClass.class") => new IncludeFromJar("jarname.jar")
case x => (mergeStrategy in assembly).value(x)
}
【讨论】:
MergeStrategy 才能做到这一点。请检查我的更新答案。
你们使用的是什么版本的sbtassembly?
我相信我使用的是不同的版本(0.14.2),因为我在使用 use project/IncludeFromJar.scala 时遇到了错误。
编译时出现以下错误:
method apply cannot override final member
def apply(args: (File, String, Seq[File])): Either[String, Seq[(File, String)]] = {
^
经过进一步调查,我发现sbtassembly.MergeStrategy 的apply 方法是最终的。因此,IncludeFromJar 的apply 方法不能覆盖sbtassembly.MergeStrategy 的即使在IncludeFromJar 中指定了override def apply
谢谢:)
【讨论】:
讨论可能有点晚了,但为了帮助其他发现此问题的人:
当你扩展 MergeStrategy 时,你想用签名覆盖方法 apply:
def apply(tempDir: File, path: String, files: Seq[File]): Either[String, Seq[(File, String)]]
以元组参数结尾的apply方法,调用apply,参数如上拆分
所以例子变成了:
def includeFromJar(val jarName: String): sbtassembly.MergeStrategy = new sbtassembly.MergeStrategy {
val name = "includeFromJar"
def apply(tmp: File, path: String, files: Seq[File]): Either[String, Seq[(File, String)]] = {
val includedFiles = files.flatMap { f =>
val (source, _, _, isFromJar) = sbtassembly.AssemblyUtils.sourceOfFileForMerge(tmp, f)
if(isFromJar && source.getName == jarName) Some(f -> path) else None
}
Right(includedFiles)
}
}
mergeStrategy in assembly := {
case PathList("path", "to", "your", "DuplicatedClass.class") => includeFromJar("jarname.jar")
case x => (mergeStrategy in assembly).value(x)
}
【讨论】: