Skip to content

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

sbt member

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.

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
sbt member

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 committed
    - 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 committed
    - 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 committed
    - 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.