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

mill.scalalib.JpackageModule.scala Maven / Gradle / Ivy

The newest version!
package mill
package scalalib

import mill._
import mill.util.Jvm

/**
 * Support for building a native package / installer with the `jpackage` tool which comes bundled with JDK 14 and later.
 *
 * The official `jpackage` docs: https://docs.oracle.com/en/java/javase/23/docs/specs/man/jpackage.html
 */
trait JpackageModule extends JavaModule {

  /** The application name */
  def jpackageName: T[String] = Task { artifactName() }

  /** The main class to use as the entry point to the native package / installer. */
  def jpackageMainClass: T[String] = Task { finalMainClass() }

  /**
   * The type of native package / installer to be created.
   *
   * Valid values are:
   *  "app-image" - any OS
   *  "dmg", "pkg" - macOS (native package, installer)
   *  "exe", "msi" - Windows (native package, installer)
   *  "rpm", "deb" - Linux
   *
   * If unspecified, defaults to "app-image" which will build a package native to the host platform.
   */
  def jpackageType: T[String] = Task { "app-image" }

  /**
   * The classpath used for the `jpackage` tool. The first entry needs to be the main jar.
   * In difference to [[runClasspath]], it contains the built jars of all dependent modules.
   */
  def jpackageRunClasspath: T[Seq[PathRef]] = Task {
    val recLocalClasspath = (localClasspath() ++ transitiveLocalClasspath()).map(_.path)

    val runCp = runClasspath().filterNot(pr => recLocalClasspath.contains(pr.path))

    val mainJar = jar()
    val recJars = transitiveJars()

    mainJar +: (recJars ++ runCp)
  }

  /** Builds a native package of the main application. */
  def jpackageAppImage: T[PathRef] = Task {
    // materialize all jars into a "lib" dir
    val libs = Task.dest / "lib"
    val cp = jpackageRunClasspath().map(_.path)
    val jars = cp.filter(os.exists).zipWithIndex.map { case (p, idx) =>
      val dest = libs / s"${idx + 1}-${p.last}"
      os.copy(p, dest, createFolders = true)
      dest
    }

    val appName = jpackageName()
    val appType = jpackageType()
    val mainClass = jpackageMainClass()
    val mainJarName = jars.head.last

    val args: Seq[String] = Seq(
      Jvm.jdkTool("jpackage", this.zincWorker().javaHome().map(_.path)),
      "--type",
      appType,
      "--name",
      appName,
      "--input",
      libs.toString(),
      "--main-jar",
      mainJarName,
      "--main-class",
      mainClass
    )

    // run jpackage tool
    val outDest = Task.dest / "image"
    os.makeDir.all(outDest)
    os.proc(args).call(cwd = outDest)
    PathRef(outDest)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy