scala deployment sbt executable-jar sbt-assembly

scala - Problemas de estrategia de combinación de ensamblado utilizando sbt-assembly



deployment executable-jar (5)

Acabo de configurar un pequeño proyecto sbt que necesita volver a cablear algunas estrategias de combinación y encontré la respuesta un poco desactualizada. Permítame agregar mi código de trabajo para las versiones (del 4-7-2015)

  • sbt 0.13.8
  • Scala 2.11.6
  • montaje 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) }

Estoy tratando de convertir un proyecto de scala en un frasco desplegable de grasa utilizando sbt-assembly . Cuando ejecuto mi tarea de ensamblaje en sbt, aparece el siguiente error:

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

Ahora desde la documentación de sbt-assembly:

Si varios archivos comparten la misma ruta relativa (por ejemplo, un recurso llamado application.conf en múltiples archivos JAR de dependencia), la estrategia predeterminada es verificar que todos los candidatos tengan el mismo contenido y que, de lo contrario, se produzca un error. Este comportamiento se puede configurar por ruta utilizando una de las siguientes estrategias integradas o escribiendo una personalizada:

  • MergeStrategy.deduplicate es el predeterminado descrito anteriormente
  • MergeStrategy.first elige el primero de los archivos coincidentes en el orden de classpath
  • MergeStrategy.last escoge el último
  • MergeStrategy.singleOrError rescata con un mensaje de error en conflicto
  • MergeStrategy.concat simplemente concatena todos los archivos coincidentes e incluye el resultado
  • MergeStrategy.filterDistinctLines también concatena, pero deja duplicados en el camino
  • MergeStrategy.rename cambia el nombre de los archivos que se originan a partir de archivos jar
  • MergeStrategy.discard simplemente descarta los archivos coincidentes

Pasando por esto, configuro mi build.sbt de la siguiente manera:

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

En la última línea del build.sbt, tengo:

mergeStrategy in assembly := mergeStrategy.first

Ahora, cuando ejecuto SBT, obtengo el siguiente error:

error: value first is not a member of sbt.SettingKey[String => sbtassembly.Plugin.MergeStrategy] mergeStrategy in assembly := mergeStrategy.first

¿Alguien puede señalar lo que podría estar haciendo mal aquí?

Gracias


Creo que debería ser MergeStrategy.first con una M mayúscula, así que mergeStrategy in assembly := MergeStrategy.first .


En cuanto a la versión actual 0.11.2 (2014-03-25), la forma de definir la estrategia de fusión es diferente.

Esto se documenta sbt-assembly , la parte relevante es:

NOTA: mergeStrategy en ensamblador espera una función, no puede hacer

mergeStrategy in assembly := MergeStrategy.first

La nueva forma es (copiada de la misma fuente):

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) } }

Posiblemente esto también sea aplicable a versiones anteriores, no sé exactamente cuándo ha cambiado.


Esta es la forma correcta de fusionar la mayoría de los proyectos comunes de Java / Scala. Cuida de META-INF y clases.

También se atiende el registro de servicio en 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}


Para la nueva versión de sbt (sbt-versión: 0.13.11), estaba recibiendo el error para slf4j; por el momento se tomó el camino fácil: Por favor, también verifique la respuesta aquí El ensamblaje de SBT de Scala no se puede combinar debido a un error de deduplicación en StaticLoggerBinder.class donde se menciona la herramienta de sbt-dependency-graph cual es muy bueno hacerlo manualmente

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