Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

add MergeStrategy, see #36 #37

Merged
merged 3 commits into from

3 participants

@rkuhn
  • split out unzipped JARs into different subdirectories under tempDir to keep duplicates
  • add MergeStrategy, which is (tempDir, Seq[File]) => File
  • subject all duplicate entries to the merge strategy as obtained from the mergeStrategy setting (which is String => MergeStrategy)
  • replace previous handling of META-INF/services/* with MergeStrategy.uniqueLines
  • set default strategy for "reference.conf" to MergeStrategy.append
  • everything else defaults to MergeStrategy.error
  • also add pickFirst/pickLast strategies
@rkuhn rkuhn add MergeStrategy, see #36
- split out unzipped JARs into different subdirectories under tempDir to
  keep duplicates
- add MergeStrategy, which is (tempDir, Seq[File]) => File
- subject all duplicate entries to the merge strategy as obtained from
  the mergeStrategy setting (which is String => MergeStrategy)
- replace previous handling of META-INF/services/* with
  MergeStrategy.uniqueLines
- set default strategy for "reference.conf" to MergeStrategy.append
- everything else defaults to MergeStrategy.error
- also add pickFirst/pickLast strategies
875e57b
@eed3si9n

The key name should be "assembly-merge-strategy" per best practice convention.

okay, will do

@eed3si9n

If we're doing the append, why not call pickFirst and pickLast head and last?

I’m beginning to see Mathias’ point: they should be high-level descriptions, so I’m leaning towards keeping these and rename append to concat (which interpreted as “concatenating line containers” also matches Unix tradition).

Owner

Given that your strategy takes Seq[File], concat probably makes more sense even from my low-level naming style.
I think head and last can still make sense here, esp given that our audience are programmers.

Owner

A question out of curiosity:
Is the order of the colliding files stable and controllable by the user?
If not, then pickFirst and pickLast probably don't really make sense and a pickOne strategy (implemented, for example, identically to the current pickFirst) might make more sense.

Classpaths are sensitive to ordering, so I sure hope that SBT does not mix them up, and as far as I can see sbt-assembly keeps them in this order. The only thing I’m unsure about is the PathFinder.get which constructs the descendants. So, I think first and last should make sense.

@eed3si9n

Cool use of groupBy.

I’ve been looking for an opportunity to use this for a long time ;-)

@rkuhn rkuhn rename append->concat, add mustEqual and tests
- add new strategy `mustEqual`, which is pickFirst if the files’
  contents do match
- make mustEqual the default action
3a44476
@rkuhn rkuhn improve logging and document merge strategies
- also change names to "first", "last", "deduplicate",
  "filterDistinctLines"
ba89523
@rkuhn

Everything’s ready from my side, so merge away (unless there are issues, of course).

@eed3si9n eed3si9n merged commit 633d447 into sbt:master
@eed3si9n
Owner

Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 21, 2012
  1. @rkuhn

    add MergeStrategy, see #36

    rkuhn authored
    - split out unzipped JARs into different subdirectories under tempDir to
      keep duplicates
    - add MergeStrategy, which is (tempDir, Seq[File]) => File
    - subject all duplicate entries to the merge strategy as obtained from
      the mergeStrategy setting (which is String => MergeStrategy)
    - replace previous handling of META-INF/services/* with
      MergeStrategy.uniqueLines
    - set default strategy for "reference.conf" to MergeStrategy.append
    - everything else defaults to MergeStrategy.error
    - also add pickFirst/pickLast strategies
Commits on Apr 22, 2012
  1. @rkuhn

    rename append->concat, add mustEqual and tests

    rkuhn authored
    - add new strategy `mustEqual`, which is pickFirst if the files’
      contents do match
    - make mustEqual the default action
Commits on Apr 23, 2012
  1. @rkuhn

    improve logging and document merge strategies

    rkuhn authored
    - also change names to "first", "last", "deduplicate",
      "filterDistinctLines"
This page is out of date. Refresh to see the latest.
Showing with 299 additions and 45 deletions.
  1. +34 −0 README.md
  2. +1 −1  build.sbt
  3. +2 −0  notes/0.7.5.markdown
  4. +104 −40 src/main/scala/sbtassembly/Plugin.scala
  5. +1 −1  src/sbt-test/sbt-assembly/config/project/plugins.sbt
  6. +1 −1  src/sbt-test/sbt-assembly/deps/project/plugins.sbt
  7. +1 −1  src/sbt-test/sbt-assembly/empty/project/plugins.sbt
  8. BIN  src/sbt-test/sbt-assembly/mergefail/lib/1.jar
  9. BIN  src/sbt-test/sbt-assembly/mergefail/lib/2.jar
  10. BIN  src/sbt-test/sbt-assembly/mergefail/lib/3.jar
  11. +18 −0 src/sbt-test/sbt-assembly/mergefail/project/Build.scala
  12. +1 −0  src/sbt-test/sbt-assembly/mergefail/project/plugins.sbt
  13. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/1/a
  14. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/1/b
  15. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/1/c
  16. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/1/d
  17. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/1/e
  18. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/2/a
  19. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/2/b
  20. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/2/c
  21. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/2/d
  22. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/2/e
  23. +2 −0  src/sbt-test/sbt-assembly/mergefail/src/main/3/a
  24. +2 −0  src/sbt-test/sbt-assembly/mergefail/src/main/3/b
  25. +2 −0  src/sbt-test/sbt-assembly/mergefail/src/main/3/c
  26. +2 −0  src/sbt-test/sbt-assembly/mergefail/src/main/3/d
  27. +1 −0  src/sbt-test/sbt-assembly/mergefail/src/main/3/e
  28. +4 −0 src/sbt-test/sbt-assembly/mergefail/src/main/mklibs.sh
  29. +2 −0  src/sbt-test/sbt-assembly/mergefail/test
  30. BIN  src/sbt-test/sbt-assembly/mergefail2/lib/1.jar
  31. BIN  src/sbt-test/sbt-assembly/mergefail2/lib/2.jar
  32. BIN  src/sbt-test/sbt-assembly/mergefail2/lib/3.jar
  33. +14 −0 src/sbt-test/sbt-assembly/mergefail2/project/Build.scala
  34. +1 −0  src/sbt-test/sbt-assembly/mergefail2/project/plugins.sbt
  35. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/1/a
  36. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/1/b
  37. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/1/c
  38. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/1/d
  39. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/1/e
  40. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/2/a
  41. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/2/b
  42. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/2/c
  43. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/2/d
  44. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/2/e
  45. +2 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/3/a
  46. +2 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/3/b
  47. +2 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/3/c
  48. +2 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/3/d
  49. +1 −0  src/sbt-test/sbt-assembly/mergefail2/src/main/3/e
  50. +4 −0 src/sbt-test/sbt-assembly/mergefail2/src/main/mklibs.sh
  51. +2 −0  src/sbt-test/sbt-assembly/mergefail2/test
  52. BIN  src/sbt-test/sbt-assembly/merging/lib/1.jar
  53. BIN  src/sbt-test/sbt-assembly/merging/lib/2.jar
  54. BIN  src/sbt-test/sbt-assembly/merging/lib/3.jar
  55. +40 −0 src/sbt-test/sbt-assembly/merging/project/Build.scala
  56. +1 −0  src/sbt-test/sbt-assembly/merging/project/plugins.sbt
  57. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/1/a
  58. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/1/b
  59. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/1/c
  60. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/1/d
  61. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/1/e
  62. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/2/a
  63. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/2/b
  64. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/2/c
  65. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/2/d
  66. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/2/e
  67. +2 −0  src/sbt-test/sbt-assembly/merging/src/main/3/a
  68. +2 −0  src/sbt-test/sbt-assembly/merging/src/main/3/b
  69. +2 −0  src/sbt-test/sbt-assembly/merging/src/main/3/c
  70. +2 −0  src/sbt-test/sbt-assembly/merging/src/main/3/d
  71. +1 −0  src/sbt-test/sbt-assembly/merging/src/main/3/e
  72. +4 −0 src/sbt-test/sbt-assembly/merging/src/main/mklibs.sh
  73. +6 −0 src/sbt-test/sbt-assembly/merging/test
  74. +1 −1  src/sbt-test/sbt-assembly/simple/project/plugins.sbt
View
34 README.md
@@ -143,6 +143,40 @@ To set an explicit main class,
mainClass in assembly := Some("com.example.Main")
```
+What about Conflicts?
+---------------------
+
+If multiple files share the same relative path (e.g. a resource named
+`application.conf` in multiple dependency JARs), the default strategy is to
+verify that all candidates have the same contents and error out if that is not
+the case. This behavior can be configured on a per-path basis using either one
+of the following built-in strategies or writing a custom one:
+
+* `MergeStrategy.first` picks the first of the conflicting files in classpath order
+* `MergeStrategy.last` picks the last one
+* `MergeStrategy.error` bails out with an error message
+* `MergeStrategy.deduplicate` is the default described above
+* `MergeStrategy.concat` simply concatenates all conflicting files and includes the result
+* `MergeStrategy.filterDistinctLines` also concatenates, but leaves out duplicates along the way
+
+The mapping of path names to merge strategies is done via the setting
+`assembly-merge-strategy` which can be augmented like so:
+
+```
+mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
+ {
+ case "application.conf" => MergeStrategy.concat
+ case x => old(x)
+ }
+}
+```
+
+where the default is to
+
+* `concat` "reference.conf",
+* `filterDistinctLines` everything below "META-INF/services" and
+* `deduplicate` the rest.
+
License
-------
View
2  build.sbt
@@ -4,7 +4,7 @@ name := "sbt-assembly"
organization := "com.eed3si9n"
-version := "0.7.4"
+version := "0.7.5-SNAPSHOT"
description := "sbt plugin to create a single fat jar"
View
2  notes/0.7.5.markdown
@@ -0,0 +1,2 @@
+## minor updates
+- add merge strategies in case of conflicting resources
View
144 src/main/scala/sbtassembly/Plugin.scala
@@ -2,10 +2,11 @@ package sbtassembly
import sbt._
import Keys._
-import java.io.PrintWriter
import scala.collection.mutable
import scala.io.Source
import Project.Initialize
+import java.io.{ PrintWriter, FileOutputStream, File }
+import java.security.MessageDigest
object Plugin extends sbt.Plugin {
import AssemblyKeys._
@@ -23,12 +24,81 @@ object Plugin extends sbt.Plugin {
lazy val excludedFiles = SettingKey[Seq[File] => Seq[File]]("assembly-excluded-files")
lazy val excludedJars = TaskKey[Classpath]("assembly-excluded-jars")
lazy val assembledMappings = TaskKey[File => Seq[(File, String)]]("assembly-assembled-mappings")
+ lazy val mergeStrategy = SettingKey[String => MergeStrategy]("assembly-merge-strategy", "mapping from archive member path to merge strategy")
+ }
+
+ /**
+ * MergeStrategy is invoked if more than one source file is mapped to the
+ * same target path. Its arguments are the tempDir (which is deleted after
+ * packaging) and the sequence of source files, and it shall return the
+ * file to be included in the assembly (or throw an exception).
+ */
+ type MergeStrategy = (File, Seq[File]) => (Either[String, File], String)
+ object MergeStrategy {
+
+ val first: MergeStrategy = (tmp, files) => (Right(files.head), "first")
+
+ val last: MergeStrategy = (tmp, files) => (Right(files.last), "last")
+
+ val error: MergeStrategy = (tmp, files) =>
+ (Left("found multiple files for same target path:" + files.map(filename(tmp, _)).mkString("\n", "\n", "")), "error")
+
+ val concat: MergeStrategy = { (tmp, files) =>
+ val file = File.createTempFile("sbtMergeTarget", ".tmp", tmp)
+ val out = new FileOutputStream(file)
+ try {
+ files foreach (f => IO.transfer(f, out))
+ (Right(file), "concat")
+ } finally {
+ out.close()
+ }
+ }
+
+ val filterDistinctLines: MergeStrategy = { (tmp, files) =>
+ val lines = files flatMap (IO.readLines(_, IO.utf8))
+ val unique = (Vector.empty[String] /: lines)((v, l) => if (v contains l) v else v :+ l)
+ val file = File.createTempFile("sbtMergeTarget", ".tmp", tmp)
+ IO.writeLines(file, unique, IO.utf8)
+ (Right(file), "filterDistinctLines")
+ }
+
+ val deduplicate: MergeStrategy = { (tmp, files) =>
+ val fingerprints = Set() ++ (files map (sha1content))
+ val result =
+ if (fingerprints.size == 1) Right(files.head)
+ else Left("different file contents found in the following:" + files.map(filename(tmp, _)).mkString("\n", "\n", ""))
+ (result, "deduplicate")
+ }
+ }
+
+ private val PathRE = "([^/]+)/(.*)".r
+ private def filename(tempDir: File, f: File): String = {
+ val baseURI = tempDir.getCanonicalFile.toURI
+ val otherURI = f.getCanonicalFile.toURI
+ baseURI.relativize(otherURI) match {
+ case x if x.isAbsolute => f.getCanonicalPath
+ case relative =>
+ val PathRE(head, tail) = relative.getPath
+ val jarName = IO.read(tempDir / (head + ".jarName"), IO.utf8)
+ jarName + ":" + tail
+ }
}
private def assemblyTask(out: File, po: Seq[PackageOption], mappings: File => Seq[(File, String)],
- cacheDir: File, log: Logger): File =
+ mergeStrategy: String => MergeStrategy, cacheDir: File, log: Logger): File =
IO.withTemporaryDirectory { tempDir =>
- val srcs = mappings(tempDir)
+ val srcs: Seq[(File, String)] = mappings(tempDir).groupBy(_._2).map{
+ case (_, files) if files.size == 1 => files.head
+ case (name, files) =>
+ val result = mergeStrategy(name)(tempDir, files map (_._1)) match {
+ case (Right(f), n) =>
+ log.info("merging '%s' with strategy '%s'".format(name, n))
+ f
+ case (Left(err), n) =>
+ throw new RuntimeException(n + ": " + err)
+ }
+ (result, name)
+ }(scala.collection.breakOut)
val config = new Package.Configuration(srcs, out, po)
Package(config, cacheDir, log)
out
@@ -44,6 +114,9 @@ object Plugin extends sbt.Plugin {
case f if f.getName.toLowerCase == "manifest.mf" => f
})
}
+
+ private def sha1 = MessageDigest.getInstance("SHA-1")
+ private def sha1content(f: File) = sha1.digest(IO.readBytes(f)).toSeq
// even though fullClasspath includes deps, dependencyClasspath is needed to figure out
// which jars exactly belong to the deps for packageDependency option.
@@ -53,7 +126,6 @@ object Plugin extends sbt.Plugin {
val (libs, dirs) = classpath.map(_.data).partition(ClasspathUtilities.isArchive)
val (depLibs, depDirs) = dependencies.map(_.data).partition(ClasspathUtilities.isArchive)
- val services = mutable.Map[String, mutable.ArrayBuffer[String]]()
val excludedJars = ej map {_.data}
val libsFiltered = libs flatMap {
case jar if excludedJars contains jar.asFile => None
@@ -71,39 +143,25 @@ object Plugin extends sbt.Plugin {
if (ao.includeBin) Some(dir) else None
}
- for(jar <- libsFiltered) {
+ def sha1name(f: File): String = {
+ val bytes = f.getCanonicalPath.getBytes
+ val digest = sha1.digest(bytes)
+ ("" /: digest)(_ + "%02x".format(_))
+ }
+
+ val jarDirs = for(jar <- libsFiltered) yield {
val jarName = jar.asFile.getName
log.info("Including %s".format(jarName))
- IO.unzip(jar, tempDir)
- IO.delete(ao.exclude(Seq(tempDir)))
- val servicesDir = tempDir / "META-INF" / "services"
- if (servicesDir.asFile.exists) {
- for (service <- (servicesDir * "*").get) {
- val serviceFile = service.asFile
- if (serviceFile.exists && serviceFile.isFile) {
- val entries = services.getOrElseUpdate(serviceFile.getName, new mutable.ArrayBuffer[String]())
- for (provider <- IO.readLines(serviceFile, IO.utf8)) {
- if (!entries.contains(provider)) {
- entries += provider
- }
- }
- }
- }
- }
+ val hash = sha1name(jar)
+ IO.write(tempDir / (hash + ".jarName"), jar.getCanonicalPath, IO.utf8, false)
+ val dest = tempDir / hash
+ dest.mkdir()
+ IO.unzip(jar, dest)
+ IO.delete(ao.exclude(Seq(dest)))
+ dest
}
- for ((service, providers) <- services) {
- log.info("Merging providers for %s".format(service))
- val serviceFile = (tempDir / "META-INF" / "services" / service).asFile
- val writer = new PrintWriter(serviceFile)
- for (provider <- providers.map { _.trim }.filter { !_.isEmpty }) {
- log.debug("- %s".format(provider))
- writer.println(provider)
- }
- writer.close()
- }
-
- val base = tempDir +: dirsFiltered
+ val base = jarDirs ++ dirsFiltered
val descendants = ((base ** (-DirectoryFilter)) --- ao.exclude(base)).get filter { _.exists }
descendants x relativeTo(base)
@@ -117,17 +175,23 @@ object Plugin extends sbt.Plugin {
lazy val baseAssemblySettings: Seq[sbt.Project.Setting[_]] = Seq(
assembly <<= (test in assembly, outputPath in assembly, packageOptions in assembly,
- assembledMappings in assembly, cacheDirectory, streams) map {
- (test, out, po, am, cacheDir, s) =>
- assemblyTask(out, po, am, cacheDir, s.log) },
+ assembledMappings in assembly, mergeStrategy in assembly, cacheDirectory, streams) map {
+ (test, out, po, am, ms, cacheDir, s) =>
+ assemblyTask(out, po, am, ms, cacheDir, s.log) },
assembledMappings in assembly <<= (assemblyOption in assembly, fullClasspath in assembly, dependencyClasspath in assembly,
excludedJars in assembly, streams) map {
(ao, cp, deps, ej, s) => (tempDir: File) => assemblyAssembledMappings(tempDir, cp, deps, ao, ej, s.log) },
+
+ mergeStrategy in assembly := {
+ case "reference.conf" => MergeStrategy.concat
+ case n if n.startsWith("META-INF/services/") => MergeStrategy.filterDistinctLines
+ case _ => MergeStrategy.deduplicate
+ },
packageScala <<= (outputPath in assembly, packageOptions,
- assembledMappings in packageScala, cacheDirectory, streams) map {
- (out, po, am, cacheDir, s) => assemblyTask(out, po, am, cacheDir, s.log) },
+ assembledMappings in packageScala, mergeStrategy in assembly, cacheDirectory, streams) map {
+ (out, po, am, ms, cacheDir, s) => assemblyTask(out, po, am, ms, cacheDir, s.log) },
assembledMappings in packageScala <<= (assemblyOption in assembly, fullClasspath in assembly, dependencyClasspath in assembly,
excludedJars in assembly, streams) map {
@@ -137,8 +201,8 @@ object Plugin extends sbt.Plugin {
ej, s.log) },
packageDependency <<= (outputPath in assembly, packageOptions in assembly,
- assembledMappings in packageDependency, cacheDirectory, streams) map {
- (out, po, am, cacheDir, s) => assemblyTask(out, po, am, cacheDir, s.log) },
+ assembledMappings in packageDependency, mergeStrategy in assembly, cacheDirectory, streams) map {
+ (out, po, am, ms, cacheDir, s) => assemblyTask(out, po, am, ms, cacheDir, s.log) },
assembledMappings in packageDependency <<= (assemblyOption in assembly, fullClasspath in assembly, dependencyClasspath in assembly,
excludedJars in assembly, streams) map {
View
2  src/sbt-test/sbt-assembly/config/project/plugins.sbt
@@ -1 +1 @@
-addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.3-SNAPSHOT")
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.5-SNAPSHOT")
View
2  src/sbt-test/sbt-assembly/deps/project/plugins.sbt
@@ -1 +1 @@
-addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.3-SNAPSHOT")
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.5-SNAPSHOT")
View
2  src/sbt-test/sbt-assembly/empty/project/plugins.sbt
@@ -1 +1 @@
-addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.3-SNAPSHOT")
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.5-SNAPSHOT")
View
BIN  src/sbt-test/sbt-assembly/mergefail/lib/1.jar
Binary file not shown
View
BIN  src/sbt-test/sbt-assembly/mergefail/lib/2.jar
Binary file not shown
View
BIN  src/sbt-test/sbt-assembly/mergefail/lib/3.jar
Binary file not shown
View
18 src/sbt-test/sbt-assembly/mergefail/project/Build.scala
@@ -0,0 +1,18 @@
+package test
+
+import sbt._
+import Keys._
+import sbtassembly.Plugin._
+import AssemblyKeys._
+
+object B extends Build {
+ lazy val project = Project("testmerge", file("."),
+ settings = Defaults.defaultSettings ++ assemblySettings ++ Seq(
+ version := "0.1",
+ jarName in assembly := "foo.jar",
+ mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) => {
+ case _ => MergeStrategy.error
+ }
+ }
+ ))
+}
View
1  src/sbt-test/sbt-assembly/mergefail/project/plugins.sbt
@@ -0,0 +1 @@
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.5-SNAPSHOT")
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/1/a
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/1/b
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/1/c
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/1/d
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/1/e
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/2/a
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/2/b
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/2/c
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/2/d
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/2/e
@@ -0,0 +1 @@
+1
View
2  src/sbt-test/sbt-assembly/mergefail/src/main/3/a
@@ -0,0 +1,2 @@
+1
+3
View
2  src/sbt-test/sbt-assembly/mergefail/src/main/3/b
@@ -0,0 +1,2 @@
+1
+3
View
2  src/sbt-test/sbt-assembly/mergefail/src/main/3/c
@@ -0,0 +1,2 @@
+1
+3
View
2  src/sbt-test/sbt-assembly/mergefail/src/main/3/d
@@ -0,0 +1,2 @@
+1
+3
View
1  src/sbt-test/sbt-assembly/mergefail/src/main/3/e
@@ -0,0 +1 @@
+1
View
4 src/sbt-test/sbt-assembly/mergefail/src/main/mklibs.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+for i in 1 2 3; do
+ zip -jr ../../lib/$i.jar $i
+done
View
2  src/sbt-test/sbt-assembly/mergefail/test
@@ -0,0 +1,2 @@
+# must fail due to conflict and error strategy
+-> assembly
View
BIN  src/sbt-test/sbt-assembly/mergefail2/lib/1.jar
Binary file not shown
View
BIN  src/sbt-test/sbt-assembly/mergefail2/lib/2.jar
Binary file not shown
View
BIN  src/sbt-test/sbt-assembly/mergefail2/lib/3.jar
Binary file not shown
View
14 src/sbt-test/sbt-assembly/mergefail2/project/Build.scala
@@ -0,0 +1,14 @@
+package test
+
+import sbt._
+import Keys._
+import sbtassembly.Plugin._
+import AssemblyKeys._
+
+object B extends Build {
+ lazy val project = Project("testmerge", file("."),
+ settings = Defaults.defaultSettings ++ assemblySettings ++ Seq(
+ version := "0.1",
+ jarName in assembly := "foo.jar"
+ ))
+}
View
1  src/sbt-test/sbt-assembly/mergefail2/project/plugins.sbt
@@ -0,0 +1 @@
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.5-SNAPSHOT")
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/1/a
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/1/b
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/1/c
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/1/d
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/1/e
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/2/a
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/2/b
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/2/c
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/2/d
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/2/e
@@ -0,0 +1 @@
+1
View
2  src/sbt-test/sbt-assembly/mergefail2/src/main/3/a
@@ -0,0 +1,2 @@
+1
+3
View
2  src/sbt-test/sbt-assembly/mergefail2/src/main/3/b
@@ -0,0 +1,2 @@
+1
+3
View
2  src/sbt-test/sbt-assembly/mergefail2/src/main/3/c
@@ -0,0 +1,2 @@
+1
+3
View
2  src/sbt-test/sbt-assembly/mergefail2/src/main/3/d
@@ -0,0 +1,2 @@
+1
+3
View
1  src/sbt-test/sbt-assembly/mergefail2/src/main/3/e
@@ -0,0 +1 @@
+1
View
4 src/sbt-test/sbt-assembly/mergefail2/src/main/mklibs.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+for i in 1 2 3; do
+ zip -jr ../../lib/$i.jar $i
+done
View
2  src/sbt-test/sbt-assembly/mergefail2/test
@@ -0,0 +1,2 @@
+# must fail due to conflict and error strategy
+-> assembly
View
BIN  src/sbt-test/sbt-assembly/merging/lib/1.jar
Binary file not shown
View
BIN  src/sbt-test/sbt-assembly/merging/lib/2.jar
Binary file not shown
View
BIN  src/sbt-test/sbt-assembly/merging/lib/3.jar
Binary file not shown
View
40 src/sbt-test/sbt-assembly/merging/project/Build.scala
@@ -0,0 +1,40 @@
+package test
+
+import sbt._
+import Keys._
+import sbtassembly.Plugin._
+import AssemblyKeys._
+
+object B extends Build {
+
+ lazy val project = Project("testmerge", file("."),
+ settings = Defaults.defaultSettings ++ assemblySettings ++ Seq(
+ version := "0.1",
+ jarName in assembly := "foo.jar",
+ mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old)
+ {
+ case "a" MergeStrategy.concat
+ case "b" MergeStrategy.first
+ case "c" MergeStrategy.last
+ case "d" MergeStrategy.filterDistinctLines
+ case x old(x)
+ }
+ },
+ TaskKey[Unit]("check") <<= (target) map { (target)
+ IO.withTemporaryDirectory { dir
+ IO.unzip(target / "foo.jar", dir)
+ mustContain(dir / "a", Seq("1", "2", "1", "3"))
+ mustContain(dir / "b", Seq("1"))
+ mustContain(dir / "c", Seq("1", "3"))
+ mustContain(dir / "d", Seq("1", "2", "3"))
+ mustContain(dir / "e", Seq("1"))
+ }
+ }))
+
+ private def mustContain(f: File, l: Seq[String]) {
+ val lines = IO.readLines(f, IO.utf8)
+ if (lines != l)
+ throw new Exception("file " + f + " had wrong content:\n" + lines.mkString("\n") +
+ "\n*** instead of ***\n" + l.mkString("\n"))
+ }
+}
View
1  src/sbt-test/sbt-assembly/merging/project/plugins.sbt
@@ -0,0 +1 @@
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.5-SNAPSHOT")
View
1  src/sbt-test/sbt-assembly/merging/src/main/1/a
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/merging/src/main/1/b
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/merging/src/main/1/c
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/merging/src/main/1/d
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/merging/src/main/1/e
@@ -0,0 +1 @@
+1
View
1  src/sbt-test/sbt-assembly/merging/src/main/2/a
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/merging/src/main/2/b
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/merging/src/main/2/c
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/merging/src/main/2/d
@@ -0,0 +1 @@
+2
View
1  src/sbt-test/sbt-assembly/merging/src/main/2/e
@@ -0,0 +1 @@
+1
View
2  src/sbt-test/sbt-assembly/merging/src/main/3/a
@@ -0,0 +1,2 @@
+1
+3
View
2  src/sbt-test/sbt-assembly/merging/src/main/3/b
@@ -0,0 +1,2 @@
+1
+3
View
2  src/sbt-test/sbt-assembly/merging/src/main/3/c
@@ -0,0 +1,2 @@
+1
+3
View
2  src/sbt-test/sbt-assembly/merging/src/main/3/d
@@ -0,0 +1,2 @@
+1
+3
View
1  src/sbt-test/sbt-assembly/merging/src/main/3/e
@@ -0,0 +1 @@
+1
View
4 src/sbt-test/sbt-assembly/merging/src/main/mklibs.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+for i in 1 2 3; do
+ zip -jr ../../lib/$i.jar $i
+done
View
6 src/sbt-test/sbt-assembly/merging/test
@@ -0,0 +1,6 @@
+# check if the file gets created
+> assembly
+$ exists target/foo.jar
+
+# check if it says hello
+> check
View
2  src/sbt-test/sbt-assembly/simple/project/plugins.sbt
@@ -1 +1 @@
-addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.3-SNAPSHOT")
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.5-SNAPSHOT")
Something went wrong with that request. Please try again.