Как можно исключить дублирующий класс из сборки sbt?
Мы имеем ситуацию, когда две зависимости имеют ровно один и тот же класс (потому что одна из зависимостей скопировала его и включила в свой собственный источник).
Это приводит к тому, что sbt assembly
завершит проверку дедупликации.
Как я могу исключить класс из конкретной банки?
Ответы
Ответ 1
Вам нужна 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.scala
import 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.sbt
mergeStrategy in assembly := {
case PathList("path", "to", "your", "DuplicatedClass.class") => new IncludeFromJar("jarname.jar")
case x => (mergeStrategy in assembly).value(x)
}
Ответ 2
Какую версию 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)]] = {
^
После дальнейшего изучения я обнаружил, что apply
метода sbtassembly.MergeStrategy
является окончательным. Следовательно, метод IncludeFromJar
apply
не может переопределить sbtassembly.MergeStrategy
даже с указанием override def apply
в IncludeFromJar
Спасибо :)
Ответ 3
Возможно, немного поздно для обсуждения, но чтобы помочь другим, которые находят это:
когда вы расширяете MergeStrategy, вы хотите переопределить метод apply с помощью подписи:
def apply(tempDir: File, path: String, files: Seq[File]): Either[String, Seq[(File, String)]]
Метод apply, который является окончательным с аргументом tuple, вызывает метод apply с параметрами, выделенными как указано выше
https://github.com/sbt/sbt-assembly/blob/edd35cfbaf05c3465371b63d38fda8ac579d766c/src/main/scala/sbtassembly/MergeStrategy.scala#L19
Таким образом, пример становится:
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)
}