Skip to content

Instantly share code, notes, and snippets.

@colestanfield
Created August 8, 2014 22:55
Show Gist options
  • Save colestanfield/fac042d3108b0c06e952 to your computer and use it in GitHub Desktop.
Save colestanfield/fac042d3108b0c06e952 to your computer and use it in GitHub Desktop.
sbt-assembly merge strategy for aop.xml files
// Create a new MergeStrategy for aop.xml files
val aopMerge: MergeStrategy = new MergeStrategy {
val name = "aopMerge"
import scala.xml._
import scala.xml.dtd._
def apply(tempDir: File, path: String, files: Seq[File]): Either[String, Seq[(File, String)]] = {
val dt = DocType("aspectj", PublicID("-//AspectJ//DTD//EN", "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"), Nil)
val file = MergeStrategy.createMergeTarget(tempDir, path)
val xmls: Seq[Elem] = files.map(XML.loadFile)
val aspectsChildren: Seq[Node] = xmls.flatMap(_ \\ "aspectj" \ "aspects" \ "_")
val weaverChildren: Seq[Node] = xmls.flatMap(_ \\ "aspectj" \ "weaver" \ "_")
val options: String = xmls.map(x => (x \\ "aspectj" \ "weaver" \ "@options").text).mkString(" ").trim
val weaverAttr = if (options.isEmpty) Null else new UnprefixedAttribute("options", options, Null)
val aspects = new Elem(null, "aspects", Null, TopScope, false, aspectsChildren: _*)
val weaver = new Elem(null, "weaver", weaverAttr, TopScope, false, weaverChildren: _*)
val aspectj = new Elem(null, "aspectj", Null, TopScope, false, aspects, weaver)
XML.save(file.toString, aspectj, "UTF-8", xmlDecl = false, dt)
IO.append(file, IO.Newline.getBytes(IO.defaultCharset))
Right(Seq(file -> path))
}
}
// Use defaultMergeStrategy with a case for aop.xml
// I like this better than the inline version mentioned in assembly's README
val customMergeStrategy: String => MergeStrategy = {
case PathList("META-INF", "aop.xml") =>
aopMerge
case s =>
defaultMergeStrategy(s)
}
// Use the customMergeStrategy in your settings
mergeStrategy in assembly := customMergeStrategy
@paoloSrc
Copy link

Hello @colestanfield
I notice that with sbt 1.4.9 this cause some problem
The error message during the build is
org.xml.sax.SAXParseExceptionpublicId: -//AspectJ//DTD//EN; systemId: http://www.eclipse.org/aspectj/dtd/aspectj.dtd; lineNumber: 1; columnNumber: 2; The markup declarations contained or pointed to by the document type declaration must be well-formed.

@DmytroMitin
Copy link

With sbt 1.10.11 and sbt-assembly 2.3.1 this can be

lazy val aopMerge = CustomMergeStrategy("aopMerge") { (conflicts: Vector[Dependency]) =>
  import scala.xml.*
  import scala.xml.dtd.*

  val parser = {
    val factory = javax.xml.parsers.SAXParserFactory.newInstance
    factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
    factory.newSAXParser
  }
  val xmls: Seq[Elem] = conflicts.map { conflict =>
    Using.resource((dependency: Dependency) => dependency.stream())(conflict) { is: InputStream =>
      XML.loadXML(Source.fromInputStream(is), parser)
      // XML.load(is)
    }
  }

  val dt = DocType("aspectj", PublicID("-//AspectJ//DTD//EN", "https://www.eclipse.org/aspectj/dtd/aspectj.dtd"), Nil)
  val aspectsChildren: Seq[Node] = xmls.flatMap(_ \\ "aspectj" \ "aspects" \ "_")
  val weaverChildren: Seq[Node] = xmls.flatMap(_ \\ "aspectj" \ "weaver" \ "_")
  val options: String = xmls.map(x => (x \\ "aspectj" \ "weaver" \ "@options").text).mkString(" ").trim
  val weaverAttr = if (options.isEmpty) Null else new UnprefixedAttribute("options", options, Null)
  val aspects = new Elem(null, "aspects", Null, TopScope, false, aspectsChildren: _*)
  val weaver = new Elem(null, "weaver", weaverAttr, TopScope, false, weaverChildren: _*)
  val aspectj = new Elem(null, "aspectj", Null, TopScope, false, aspects, weaver)

  val bytes = scala.util.Using.resource(new CharArrayWriter()) { writer =>
    XML.write(writer, aspectj, "UTF-8", xmlDecl = false, dt)
    (writer.toString + IO.Newline).getBytes(IO.defaultCharset)
  }

  Right(Vector(JarEntry(conflicts.head.target, () => new java.io.ByteArrayInputStream(bytes))))
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment