使用sbt-assembly进行汇编合并策略问题

问题描述 投票:26回答:6

我正在尝试使用sbt-assembly将scala项目转换为可部署的胖罐。当我在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文档:

如果多个文件共享相同的相对路径(例如,多个依赖项JAR中名为application.conf的资源),则默认策略是验证所有候选项具有相同的内容,否则出错。可以使用以下内置策略之一或编写自定义策略在每个路径的基础上配置此行为:

  • 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

有人能指出我在这里做错了什么吗?

谢谢

scala deployment sbt executable-jar sbt-assembly
6个回答
6
投票

我认为它应该是MergeStrategy.first与资本M,所以mergeStrategy in assembly := MergeStrategy.first


13
投票

对于当前版本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)
  }
}

这也可能适用于早期版本,我不确切知道它何时发生了变化。


8
投票

我刚刚设置了一个需要重新连接一些mergeStrategies的sbt项目,并且发现答案有点过时,让我添加我的工作代码版本(截至4-7-2015)

  • sbt 0.13.8
  • 比例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", xs@_ *) => MergeStrategy.last // For Log$Logger.class case x => val oldStrategy = (mergeStrategy in assembly).value oldStrategy(x) }

4
投票

对于新的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
  }
}

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}

0
投票

快速更新:不推荐使用mergeStrategy。使用assemblyMergeStrategy。除此之外,早期的反应仍然很可靠

© www.soinside.com 2019 - 2024. All rights reserved.