Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I disable jar compression in sbt using sbtassembly?

Tags:

sbt

I'm interested in building uncompressed jar files to make my rsync faster when only a few classes change and so far, i can't figure out how to tell sbtassembly to disable compression.

server > inspect assembly
[info] Task: java.io.File
[info] Description:
[info]  Builds a single-file deployable jar.
[info] Provided by:
[info]  {file:/.../}server/*:assembly
[info] Dependencies:
[info]  server/*:assembly-merge-strategy(for assembly)
[info]  server/*:assembly-output-path(for assembly)
[info]  server/*:package-options(for assembly)
[info]  server/*:assembly-assembled-mappings(for assembly)
[info]  server/*:cache-directory
[info]  server/*:test(for assembly)
[info]  server/*:streams(for assembly)
[info] Delegates:
[info]  server/*:assembly
[info]  {.}/*:assembly
[info]  */*:assembly

...

server > inspect assembly-option(for assembly)
[info] Setting: sbtassembly.AssemblyOption = AssemblyOption(true,true,true,<function1>)
[info] Description:
[info]  
[info] Provided by:
[info]  {file:/.../}server/*:assembly-option(for assembly)
[info] Dependencies:
[info]  server/*:assembly-assemble-artifact(for package-bin)
[info]  server/*:assembly-assemble-artifact(for assembly-package-scala)
[info]  server/*:assembly-assemble-artifact(for assembly-package-dependency)
[info]  server/*:assembly-excluded-files(for assembly)
...

AssemblyOption doesn't say anything about packaging, however, and the plugin seems to use sbt's own Package for that, so maybe there's a way to configure that? Package, in turn, calls IO.jar(...) to write the file. That uses withZipOutput to make a ZipOutputStream (or a JarOutputStream), on which i'd want to call setMethod(ZipOutputStream.STORED), but i can't.

Any ideas other than an sbt feature request?

like image 762
Rob Starling Avatar asked Oct 05 '22 22:10

Rob Starling


1 Answers

There is no way to do this directly via sbt configuration, since sbt assumes that any files within zip and jar artifacts should be compressed.

One workaround is to unzip and re-zip (without compression) the jar file. You can do this by adding the following setting to your project (e.g. in build.sbt):

packageBin in Compile <<= packageBin in Compile map { file =>
  println("(Re)packaging with zero compression...")
  import java.io.{FileInputStream,FileOutputStream,ByteArrayOutputStream}
  import java.util.zip.{CRC32,ZipEntry,ZipInputStream,ZipOutputStream}
  val zis = new ZipInputStream(new FileInputStream(file))
  val tmp = new File(file.getAbsolutePath + "_decompressed")
  val zos = new ZipOutputStream(new FileOutputStream(tmp))
  zos.setMethod(ZipOutputStream.STORED)
  Iterator.continually(zis.getNextEntry).
    takeWhile(ze => ze != null).
    foreach { ze =>
      val baos = new ByteArrayOutputStream
      Iterator.continually(zis.read()).
        takeWhile(-1 !=).
        foreach(baos.write)
      val bytes = baos.toByteArray
      ze.setMethod(ZipEntry.STORED)
      ze.setSize(baos.size)
      ze.setCompressedSize(baos.size)
      val crc = new CRC32
      crc.update(bytes)
      ze.setCrc(crc.getValue)
      zos.putNextEntry(ze)
      zos.write(bytes)
      zos.closeEntry
      zis.closeEntry
    } 
  zos.close
  zis.close
  tmp.renameTo(file)
  file
}

Now when you run package in sbt, the final jar file will be uncompressed, which you can verify with unzip -vl path/to/package.jar.

like image 51
earldouglas Avatar answered Oct 10 '22 04:10

earldouglas