Как исключить дублирующийся класс из сборки sbt?

У нас есть ситуация, когда две зависимости имеют один и тот же класс (потому что одна из зависимостей скопировала его и включила в свой собственный источник).

Это вызывает sbt assembly провалить свои проверки дедупликации.

Как я могу исключить класс из определенной банки?

2 ответа

Решение

Тебе необходимо mergeStrategy, который займет один из файлов.

mergeStrategy in assembly := {
    case PathList("path", "to", "your", "DuplicatedClass.class") => MergeStrategy.first
    case x => (mergeStrategy in assembly).value(x)
}

Обновить

Если вы хотите обрабатывать файл в зависимости от 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)
}

Какая версия 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"s apply метод является окончательным. Следовательно, IncludeFromJar"s apply метод не может переопределить sbtassembly.MergeStrategyдаже с указанием override def apply в IncludeFromJar

Спасибо:)

Возможно, немного поздно для обсуждения, но чтобы помочь другим, которые это нашли:

когда вы расширяете MergeStrategy, вы хотите переопределить метод apply с подписью:

 def apply(tempDir: File, path: String, files: Seq[File]): Either[String, Seq[(File, String)]]

Метод apply, который завершается с аргументом кортежа, вызывает метод apply с разделенными параметрами, как указано выше.

https://github.com/sbt/sbt-assembly/blob/edd35cfbaf05c3465371b63d38fda8ac579d766c/src/main/scala/sbtassembly/MergeStrategy.scala

Таким образом, пример становится:

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)
}
Другие вопросы по тегам