Подтвердить что ты не робот

Проблемы сборки-слияния с использованием sbt-assembly

Я пытаюсь преобразовать проект scala в развернутую масляную банку, используя sbt-assembly. Когда я запускаю задачу сборки в 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

Может кто-нибудь указать, что я могу делать неправильно здесь?

Спасибо

4b9b3361

Ответ 1

Я думаю, что это должно быть MergeStrategy.first с капиталом M, поэтому mergeStrategy in assembly := MergeStrategy.first.

Ответ 2

Что касается текущей версии 0.11.2 (2014-03-25), то способ определения стратегии слияния отличается.

Это документировано здесь, соответствующая часть:

Примечание:   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)
  }
}

Возможно, это применимо и к более ранним версиям, я точно не знаю, когда он изменился.

Ответ 3

Я только что установил небольшой проект sbt, который должен перепрофилировать некоторые mergeStrategies, и нашел ответ немного устаревшим, позвольте мне добавить мой рабочий код для версий (начиная с 4-7-2015)

  • 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", [email protected]_ *) => MergeStrategy.last // For Log$Logger.class
      case x =>
         val oldStrategy = (mergeStrategy in assembly).value
         oldStrategy(x)
    }
    

Ответ 4

Для новой версии sbt (sbt-версия: 0.13.11) я получал ошибку для slf4j; на время проделали легкий путь: пожалуйста, также проверьте ответ здесь Scala Сборка SBT не может объединиться из-за ошибки дедупликации в StaticLoggerBinder.class, где sbt-dependency-graph, который довольно круто сделать это вручную

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

Ответ 5

это правильный способ объединить большинство общих проектов 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}

Ответ 6

Быстрое обновление: mergeStrategy устарела. Используйте AssemblyMergeStrategy. Кроме того, предыдущие ответы все еще твердые

Ответ 7

Добавьте следующее в 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
 }