All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.build.internal.ManifestJar.scala Maven / Gradle / Ivy

package scala.build.internal

import java.io.OutputStream

object ManifestJar {

  /** Creates a manifest JAR, in a temporary directory or in the passed scratched directory
    *
    * @param classPath
    *   Entries that should be put in the manifest class path
    * @param wrongSimplePaths
    *   Write paths slightly differently in manifest, so that tools such as native-image accept them
    *   (but the manifest JAR can't be passed to 'java -cp' any more on Windows)
    * @param scratchDirOpt
    *   an optional scratch directory to write the manifest JAR under
    */
  def create(
    classPath: Seq[os.Path],
    wrongSimplePaths: Boolean = false,
    scratchDirOpt: Option[os.Path] = None
  ): os.Path = {
    import java.util.jar._
    val manifest   = new Manifest
    val attributes = manifest.getMainAttributes
    attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0")
    attributes.put(
      Attributes.Name.CLASS_PATH,
      if (wrongSimplePaths)
        // For tools, such as native-image, that don't correctly handle paths in manifests…
        classPath.map(_.toString).mkString(" ")
      else
        // Paths are encoded this weird way in manifest JARs. This matters on Windows in particular,
        // where paths like "C:\…" don't work fine.
        classPath.map(_.toNIO.toUri.getRawPath).mkString(" ")
    )
    val jarFile = scratchDirOpt match {
      case Some(scratchDir) =>
        os.makeDir.all(scratchDir)
        os.temp(dir = scratchDir, prefix = "classpathJar", suffix = ".jar", deleteOnExit = false)
      case None =>
        os.temp(prefix = "classpathJar", suffix = ".jar")
    }
    var os0: OutputStream    = null
    var jos: JarOutputStream = null
    try {
      os0 = os.write.outputStream(jarFile)
      jos = new JarOutputStream(os0, manifest)
    }
    finally {
      if (jos != null)
        jos.close()
      if (os0 != null)
        os0.close()
    }
    jarFile
  }

  /** Runs a block of code using a manifest JAR.
    *
    * See [[create]] for details about the parameters.
    */
  def maybeWithManifestClassPath[T](
    createManifest: Boolean,
    classPath: Seq[os.Path],
    wrongSimplePathsInManifest: Boolean = false
  )(
    f: Seq[os.Path] => T
  ): T =
    if (createManifest) {
      var toDeleteOpt = Option.empty[os.Path]

      try {
        val manifestJar = create(classPath, wrongSimplePaths = wrongSimplePathsInManifest)
        toDeleteOpt = Some(manifestJar)
        f(Seq(manifestJar))
      }
      finally
        for (toDelete <- toDeleteOpt)
          os.remove(toDelete)
    }
    else
      f(classPath)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy