├── .gitignore ├── doc ├── advanced.md ├── enabling.md ├── examples.md ├── other.md ├── packaging.md ├── paths.md └── running.md ├── project └── cross-build.sbt ├── readme.md ├── sbt-javafx.sbt └── src └── main └── scala └── no └── vedaadata └── sbtjavafx └── JavaFXPlugin.scala /.gitignore: -------------------------------------------------------------------------------- 1 | target/ -------------------------------------------------------------------------------- /doc/advanced.md: -------------------------------------------------------------------------------- 1 | ### Manually edit *build.xml* when packaging 2 | 3 | For experimenting with JavaFX packaging options that are not (yet) supported by the plugin, you might want to manually edit the intermediate *build.xml* file. 4 | 5 | To do this you'll have to prepare the build file and run it as seperate steps. 6 | 7 | To prepare the build file: execute the `javafx-prepare-build` task. 8 | 9 | (Now you can edit it.) 10 | 11 | To run the build file: execute the `javafx-run-build` task. 12 | 13 | The standard `package-javafx` task simply executes these two tasks one after another. 14 | 15 | 16 | ### Transform the *build.xml* file programmatically 17 | 18 | As a complementary feature to the above, it is also possible to automate any editing of the XML that gets written to the *build.xml* file. 19 | 20 | For this, you define a transformation function that takes the generated build XML as a parameter and returns XML possible transformed by your code: 21 | 22 | ```scala 23 | JFX.transformXml := { xml => 24 | // process it here (not shown) 25 | xml 26 | } 27 | ``` 28 | 29 | ### Post-process the packaged artifact 30 | 31 | If you want to do some custom processing of the finished packaged artifact (such as creating a zip file of it or copying it elsewhere), you can add a post-processing hook like this: 32 | 33 | ```scala 34 | JFX.postProcess <<= name { n => { dir => 35 | val imageDir = dir / "bundles" / n 36 | println("postprocessing " + imageDir) // or do something useful 37 | } } 38 | ``` -------------------------------------------------------------------------------- /doc/enabling.md: -------------------------------------------------------------------------------- 1 | ## Enabling the plugin 2 | 3 | There are two steps to enabling the plugin: 4 | 5 | Adding the following line to an `.sbt` file in the `project` directory: 6 | 7 | ```scala 8 | addSbtPlugin("no.vedaadata" %% "sbt-javafx" % "0.7") 9 | ``` 10 | 11 | (This makes the plugin available to your project.) 12 | 13 | And adding the following line to your build `.sbt` file: 14 | 15 | ```scala 16 | jfxSettings 17 | ``` 18 | 19 | (This overrides some of SBT's predefined settings in order to enable the plugin's functionality.) 20 | -------------------------------------------------------------------------------- /doc/examples.md: -------------------------------------------------------------------------------- 1 | ## Examples 2 | 3 | Some [examples of using the plugin](https://github.com/kavedaa/sbt-javafx-examples) are available. 4 | 5 | (It is possible that the examples may not be 100% in sync with the current version of the plugin at any given time, but they should still be illustrative of the concepts.) 6 | 7 | 8 | -------------------------------------------------------------------------------- /doc/other.md: -------------------------------------------------------------------------------- 1 | ## Other settings 2 | 3 | 4 | ### Application info 5 | 6 | The following keys allow specification of additional metadata for the installer and application manifest. Details are provided in the [fx:info JavaFX Ant Task Reference](http://docs.oracle.com/javafx/2/deployment/javafx_ant_task_reference.htm#CIAIEJHG). Note: the default value for `JFX.appVersion` is `sbt.Keys.version`. 7 | 8 | ```scala 9 | JFX.vendor := "ACME Inc." 10 | 11 | JFX.appVersion := "1.0-rc1" 12 | 13 | JFX.title := "Rocket Launcher" 14 | 15 | JFX.category := "Mission critical" 16 | 17 | JFX.description := "Launches rockets" 18 | 19 | JFX.copyright := "ACME 2013" 20 | 21 | JFX.license := "ACME" 22 | ``` 23 | 24 | ### Signing 25 | 26 | Application component signing may be required for JNLP, Applet, and native installer deployments, depending on platform and security settings. See the [fx:signjar JavaFX Ant Task Reference](http://docs.oracle.com/javafx/2/deployment/javafx_ant_task_reference.htm#CIADDAEE) for details. 27 | 28 | 29 | ```scala 30 | JFX.elevated := true 31 | 32 | JFX.keyStore := Some("path/to/keystore") 33 | 34 | JFX.storePass := Some("mypassword") 35 | 36 | JFX.alias := Some("myalias") 37 | 38 | JFX.keyPass := Some("mykeypass") 39 | ``` 40 | 41 | ### Platform settings 42 | 43 | ```scala 44 | JFX.javafx := Some("8.0") 45 | 46 | JFX.j2se := Some("8.0") 47 | 48 | JFX.jvmargs ++= Seq("-Xmx400m", "-verbose:jni") 49 | 50 | JFX.jvmuserargs += "-Xmx" -> "768m" 51 | 52 | JFX.properties += "purpose" -> "sample value" 53 | ``` 54 | 55 | ### Convert CSS to binary 56 | 57 | ```scala 58 | JFX.cssToBin := true 59 | ``` 60 | 61 | ### Add custom JAR manifest entries 62 | 63 | Add custom manifest entries to the jar created by the plugin, for example: 64 | 65 | ```scala 66 | packageOptions in JFX.packageJavaFx += sbt.Package.ManifestAttributes(java.util.jar.Attributes.Name.IMPLEMENTATION_VENDOR -> "Acme Inc.") 67 | ``` 68 | -------------------------------------------------------------------------------- /doc/packaging.md: -------------------------------------------------------------------------------- 1 | ## Packaging 2 | 3 | A JavaFX application must have a main class that extends from `javafx.application.Application`, e.g.: 4 | 5 | ```scala 6 | class MyJavaFXApplication extends Application { 7 | 8 | // application here 9 | } 10 | ``` 11 | 12 | The name of this class must be configured like this: 13 | 14 | ```scala 15 | JFX.mainClass := Some("mypackage.MyJavaFXApplication") 16 | ``` 17 | 18 | Execute the `package-javafx` task to package the application. 19 | 20 | The packaged application will reside inside `target///`, e.g. `target/scala_2.9.2/my-javafx-application_2.9.2-1.0/`. (It is possible to customize the name of the directory.) 21 | 22 | The application will be identical to one packaged with JavaFX's Ant tools, e.g. by using the Netbeans IDE. It will contains, at least, a `.jar` fil, a `.jnlp` file, an `.html` file, as well as a `lib/` directory with all library jars added via any of SBT's library management methods, including the standard Scala library. 23 | 24 | ### Native bundles 25 | 26 | For creating so-called "native bundles", that is, self-contained applications which co-bundles the JRE, use this setting: 27 | 28 | ```scala 29 | JFX.nativeBundles := bundleType // where bundleType is a String 30 | ``` 31 | A typical value for `bundleType` is one of: 32 | 33 | * `all` - create all native bundles available on build platform (e.g. `msi` and `exe` on Windows, `dmg` on MacOS X, etc.) 34 | * `deb` - Debian installer file (Linux only) 35 | * `dmg` - MacOS X disk image (MacOS X only) 36 | * `exe` - Windows stand-alone installer (Windows only) 37 | * `image` - `.jar`-only distribution 38 | * `msi` - Windows "installer database" file (Windows only) 39 | * `none` - Don't make native bundle (default) 40 | * `rpm` - Redhat Package Manager file (Linux only) 41 | 42 | 43 | See the [JavaFX packaging documentation](http://docs.oracle.com/javafx/2/deployment/self-contained-packaging.htm) for possible values and further information. 44 | 45 | #### Drop-in Packaging Resources 46 | 47 | As described in the article [Native Packaging Cookbook](https://blogs.oracle.com/talkingjavadeployment/entry/native_packaging_cookbook_using_drop), the native installers generated for each platform may be customized with modified versions of files from the installer templates. The Oracle-provided `fx:deploy` task in `ant-javafx.jar` is not very flexible with regard to this specification of these "drop-in" resources, so tweaking an installer can be frustrating the first time around. Any encountered problems are likely to be associated with mis-named or mis-located files, and *not* a problem with **sbt-javafx**. For an example build configuration, see the `example-packaging` source in the [examples repository](https://github.com/kavedaa/sbt-javafx-examples). 48 | 49 | At the heart of the process of specifying the location of drop-in resources is ensuring the classpath of the ClassLoader executing `fx:deploy` can resolve the desired resources. The **sbt-javafx** plugin provides the `JFX.pkgResourcesDir` setting for prepending a path to the `fx:deploy` classpath (which is *not* the same as the SBT classpath or the `scalac` classpath). 50 | 51 | For example, if a custom `Info.plist` file for MacOS X is defined in `src/deploy/package/macosx/Info.plist`, the following setting would make it visible to the `fx:deploy` ant task: 52 | 53 | ```scala 54 | JFX.pkgResourcesDir := baseDirectory.value + "/src/deploy" 55 | ``` 56 | 57 | (This is also the default.) 58 | 59 | Note that the placement of `Info.plist` in `package/macosx` is a requirement imposed by `fx:deploy`, not **sbt-javafx**. 60 | 61 | When the `fx:deploy` ant task is run with attribute `verbose="true"`, a list of customizable files is reported to the ant console, and defaults saved to a temporary directory for copying. If customized versions of these files are placed in a specific location in the classpath for `ant-javafx.jar`'s ClassLoader. This classpath should contain a folder called `package`. This is where the `fx:deploy` task looks for files with project- and platform-specific resource files. See the Oracle docs for specifics, but the basic structure is `package/{macosx,windows,linux}/[drop-in-resources]`. 62 | 63 | To debug the packaging process, set `JFX.verbose := true` in your `build.sbt` file, run `sbt package-javafx` at least once, and then run `ant` against the generated `target/scala-x.yz/build.xml` file (i.e. value of `crossTarget.value + "/build.xml"`). Running `ant` with the `fx:deploy` task in verbose mode simplifies the debugging process when your drop-in resources aren't being picked up by `ant-javafx.jar`, and helps understand what additional resources might be customized. As mentioned, the `fx:deploy` task is fussy about names and locations of these resource files. For example, the name of application replacement icons have to match application name, and the `package/{os-name}/` structure is required. 64 | 65 | #### Using the correct Java version 66 | 67 | Self-contained applications must be packaged using the JDK version of the JRE and not the stand-alone JRE. (On Windows, if you have installed the JDK you will probably have both.) If you attempt to use the JRE version, you will get an error message saying "jvm.dll is not found". 68 | 69 | This means that SBT must be started with the JDK version of the JRE. This can be assured by setting `JAVA_HOME` to the correct path, either globally or within SBT's `sbt.bat` startup file. Another option on Windows is to uninstall the JRE and ensure `JAVA_HOME` and applicable `PATH` entries point to the JDK binaries. 70 | 71 | ### Java-only applications 72 | 73 | It is very much possible to use the plugin to package applications written in Java. If your application uses no Scala code at all, you might want to use the `javaOnly` setting: 74 | 75 | ```scala 76 | JFX.javaOnly := true 77 | ``` 78 | 79 | This is a convenience setting that excludes the standard Scala library from being packaged with the application, and makes the output path a bit simpler, so that it becomes e.g. `target/my-javafx-application-1.0/`. 80 | -------------------------------------------------------------------------------- /doc/paths.md: -------------------------------------------------------------------------------- 1 | ## Customizing paths to necessary JavaFX files 2 | 3 | Two files from the JavaFX SDK are needed by the plugin: 4 | 5 | * `jfxrt.jar` (for compiling and running) 6 | * `ant-javafx.jar` (for packaging) 7 | 8 | By default these will be found automatically by the plugin. 9 | 10 | However it is possible to customize their location in different ways: 11 | 12 | ### Using JDK 7u6 or higher 13 | 14 | The JDK from version 7u6 and higher has the JavaFX SDK included with it. Specify the path to the JDK root directory like this, e.g.: 15 | 16 | ```scala 17 | JFX.devKit := JFX.jdk("C:/Program Files/Java/jdk1.7.0_06") 18 | ``` 19 | 20 | For some reason though, even if it is included, jfxrt.jar is *not* added to the Java classpath. So you'll have to add it manually in SBT, however there is a little convenience setting to do that for you: 21 | 22 | ```scala 23 | JFX.addJfxrtToClasspath := true 24 | ``` 25 | 26 | (With the longish name it might not seem so convenient, but this helps identify it as a *workaround* needed for older (pre-8) Java versions.) 27 | 28 | It is not necessary to add ant-javafx.jar to the classpath. 29 | 30 | ### Using JDK 8 or higher 31 | 32 | From JDK 8 and upwards, you don't need to add `jfxrt.jar` to the classpath (but you still need to specify `JFX.devKit` for the plugin to be able to find the packaging tool). 33 | 34 | ### Using a standalone JavaFX SDK 35 | 36 | If you're using JDK 6 (which does not include JavaFX SDK), or for some other reason prefer to use the stand-alone JavaFX SDK, specify the path to the root directory like this, e.g.: 37 | 38 | ```scala 39 | JFX.devKit := JFX.sdk("C:/Program Files/Oracle/JavaFX 2.2 SDK") 40 | ``` 41 | 42 | ### Manual configuration 43 | 44 | You can also specify the full paths to jfxrt.jar and ant-javafx.jar individually, e.g.: 45 | 46 | ```scala 47 | JFX.jfxrt := Some("C:/Program Files/Java/jdk1.7.0_07/jre/lib/jfxrt.jar") 48 | ``` 49 | ```scala 50 | JFX.antLib := Some("C:/Program Files/Java/jdk1.7.0_07/lib/ant-javafx.jar") 51 | ``` 52 | 53 | (These will take precedence over corresponding paths possibly calculated from specified JDK or SDK directory.) 54 | 55 | *Tip:* SBT does not limit you to use only a single .sbt build settings file for your project. Instead, it combines the settings from all .sbt files in your project's root directory. It is a good idea to keep the path configuration settings in a seperate file than the main build file and exclude this file from version control, especially when you're collaborating with others on the project or for other reasons compiling it on several different machines where the paths may not be the same. (Note that SBT seems to load the `.sbt` files in alphabetical order, which sometimes matters...) 56 | 57 | -------------------------------------------------------------------------------- /doc/running.md: -------------------------------------------------------------------------------- 1 | ## Running from within SBT 2 | 3 | SBT is not able to launch a `javafx.application.Application` on its own. It needs a class with a static `main` method for its `run` task, which name must be configured in the `mainClass` setting (which is distinct from `JFX.mainClass`). 4 | 5 | By default, the plugin will set SBT's `mainClass` to the same value as `JFX.mainClass`. This makes it simple to add the necessary launcher code. 6 | 7 | ### Scala-centric applications 8 | 9 | You can use a companion object with a `main` method that has code to launch the JavaFX application, e.g.: 10 | 11 | ```scala 12 | object MyJavaFXApplication { 13 | def main(args: Array[String]) { 14 | Application launch(classOf[MyJavaFXApplication], args: _*) 15 | } 16 | } 17 | ``` 18 | 19 | If you for some reason would want to name this differently, you can override SBT's `mainClass` like this, e.g.: 20 | 21 | ```scala 22 | mainClass in (Compile, run) := Some("some.other.Launcher") 23 | ``` 24 | 25 | ### Java-centric applications 26 | 27 | You can add a static `main` method to your JavaFX application class, e.g.: 28 | 29 | 30 | ```java 31 | public class MyJavaFXApplication extends Application { 32 | 33 | public static void main(String[] args) { 34 | Application.launch(args); 35 | } 36 | 37 | // rest of application here 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /project/cross-build.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.8.1") -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # sbt-javafx 2 | 3 | sbt-javafx is a plugin for [SBT](http://www.scala-sbt.org/) (Simple Build Tool) for packaging JavaFX applications. 4 | 5 | ## Quick start 6 | 7 | Add an `.sbt` file (e.g. `plugins.sbt`) to the project's `project` directory, with the following content: 8 | 9 | ```scala 10 | addSbtPlugin("no.vedaadata" %% "sbt-javafx" % "0.7") 11 | ``` 12 | 13 | A minimal `.sbt` build file (e.g. `build.sbt`) could then look like this: 14 | 15 | ```scala 16 | name := "my-javafx-application" 17 | 18 | jfxSettings 19 | 20 | JFX.mainClass := Some("mypackage.MyJavaFXApplication") 21 | ``` 22 | 23 | To package the application, simply run the `package-javafx` task. 24 | 25 | More details: 26 | 27 | * [Enabling the plugin](doc/enabling.md) 28 | * [Customizing paths to necessary JavaFX files](doc/paths.md) 29 | * [Running from within SBT](doc/running.md) 30 | * [Packaging](doc/packaging.md) 31 | * [Other settings](doc/other.md) 32 | * [Advanced features](doc/advanced.md) 33 | * [Examples](https://github.com/kavedaa/sbt-javafx-examples) -------------------------------------------------------------------------------- /sbt-javafx.sbt: -------------------------------------------------------------------------------- 1 | name := "sbt-javafx" 2 | 3 | organization := "no.vedaadata" 4 | 5 | version := "0.7.1-SNAPSHOT" 6 | 7 | sbtPlugin := true 8 | 9 | crossBuildingSettings 10 | 11 | CrossBuilding.crossSbtVersions := Seq("0.11.2", "0.11.3", "0.12", "0.13") 12 | 13 | libraryDependencies += "org.apache.ant" % "ant" % "1.8.2" 14 | 15 | publishMavenStyle := true 16 | 17 | publishTo <<= version { (v: String) => 18 | val nexus = "https://oss.sonatype.org/" 19 | if (v.trim.endsWith("SNAPSHOT")) 20 | Some("snapshots" at nexus + "content/repositories/snapshots") 21 | else 22 | Some("releases" at nexus + "service/local/staging/deploy/maven2") 23 | } 24 | 25 | publishArtifact in Test := false 26 | 27 | pomIncludeRepository := { _ => false } 28 | 29 | pomExtra := ( 30 | https://github.com/kavedaa/sbt-javafx 31 | 32 | 33 | BSD-style 34 | http://www.opensource.org/licenses/bsd-license.php 35 | repo 36 | 37 | 38 | 39 | git@github.com:kavedaa/sbt-javafx 40 | scm:git:git@github.com:kavedaa/sbt-javafx 41 | 42 | 43 | 44 | kavedaa 45 | Knut Arne Vedaa 46 | http://vedaadata.com 47 | 48 | 49 | ) -------------------------------------------------------------------------------- /src/main/scala/no/vedaadata/sbtjavafx/JavaFXPlugin.scala: -------------------------------------------------------------------------------- 1 | package no.vedaadata.sbtjavafx 2 | 3 | import sbt._ 4 | import sbt.Keys._ 5 | import classpath.ClasspathUtilities 6 | import org.apache.tools.ant 7 | import scala.xml.Elem 8 | import sbt.Package.{ JarManifest, ManifestAttributes } 9 | 10 | // Types and utils used for jdk/sdk configuration 11 | 12 | sealed trait DevKit 13 | case class JDK(path: String) extends DevKit 14 | case class SDK(path: String) extends DevKit 15 | 16 | object DevKit { 17 | def jfxrt(devKit: DevKit) = devKit match { 18 | case JDK(path) => path + "/jre/lib/jfxrt.jar" 19 | case SDK(path) => path + "/rt/lib/jfxrt.jar" 20 | } 21 | def antLib(devKit: DevKit) = devKit match { 22 | case JDK(path) => path + "/lib/ant-javafx.jar" 23 | case SDK(path) => path + "/lib/ant-javafx.jar" 24 | } 25 | def isJdk(devKit: DevKit) = devKit.isInstanceOf[JDK] 26 | } 27 | 28 | // Wrapper classes for grouping the settings, since there's a lot of them 29 | 30 | case class JFX( 31 | paths: Paths, 32 | mainClass: Option[String], 33 | output: Output, 34 | template: Template, 35 | dimensions: Dimensions, 36 | permissions: Permissions, 37 | info: Info, 38 | signing: Signing, 39 | misc: Misc) 40 | 41 | case class Paths(devKit: Option[DevKit], jfxrt: Option[String], antLib: Option[String], pkgResourcesDir: String) 42 | 43 | case class Output(nativeBundles: String, artifactBaseName: (String, ModuleID, Artifact) => String, artifactBaseNameValue: String) 44 | 45 | case class Template(file: Option[String], destFile: Option[String], placeholderId: String) 46 | 47 | case class Permissions(elevated: Boolean, cacheCertificates: Boolean) 48 | 49 | case class Signing(keyStore: Option[File], storePass: Option[String], alias: Option[String], keyPass: Option[String], storeType: Option[String]) 50 | 51 | case class Dimensions(width: Int, height: Int, embeddedWidth: String, embeddedHeight: String) 52 | 53 | case class Info(vendor: String, title: String, appVersion: String, category: String, copyright: String, description: String, license: String) 54 | 55 | case class Platform(javafx: Option[String], j2se: Option[String], jvmargs: Seq[String], jvmuserargs: Seq[(String, String)], properties: Seq[(String, String)]) 56 | 57 | case class Misc(platform: Platform, cssToBin: Boolean, verbose: Boolean, transformXml: Elem => Elem, postProcess: File => Unit) 58 | 59 | 60 | // The plugin 61 | 62 | object JavaFXPlugin extends Plugin { 63 | 64 | // Define the keys 65 | 66 | val jfx = SettingKey[JFX]("javafx", "All JavaFX settings.") 67 | 68 | object JFX { 69 | 70 | private def prefixed(name: String) = List(jfx.key.label, name) mkString "-" 71 | 72 | val devKit = SettingKey[Option[DevKit]](prefixed("dev-kit"), "Path to JDK or JavaFX SDK.") 73 | 74 | val jfxrt = SettingKey[Option[String]](prefixed("jfxrt"), "Path to jfxrt.jar.") 75 | 76 | val antLib = SettingKey[Option[String]](prefixed("ant-lib"), "Path to ant-javafx.jar.") 77 | 78 | val pkgResourcesDir = SettingKey[String](prefixed("pkg-resources-dir"), "Path containing the `package/{windows,macosx,linux}` directory, to be added to the ant-javafx.jar classpath for drop-in resources. See https://blogs.oracle.com/talkingjavadeployment/entry/native_packaging_cookbook_using_drop for details.") 79 | 80 | val paths = SettingKey[Paths](prefixed("paths"), "JavaFX paths settings.") 81 | 82 | val addJfxrtToClasspath = SettingKey[Boolean](prefixed("add-jfxrt-to-classpath"), "Whether jfxrt.jar should be added to compile and runtime classpaths.") 83 | 84 | val mainClass = SettingKey[Option[String]](prefixed("main-class"), "Entry point for JavaFX application, must extend javafx.application.Application and implement the start() method.") 85 | 86 | val javaOnly = SettingKey[Boolean](prefixed("java-only"), "Convenience setting for JavaFX applications in pure Java, sets some other settings to usable defaults for this scenario.") 87 | 88 | val output = SettingKey[Output](prefixed("output"), "JavaFX output settings.") 89 | 90 | val nativeBundles = SettingKey[String](prefixed("native-bundles"), "Which native bundles to create, if any.") 91 | val artifactBaseName = SettingKey[(String, ModuleID, Artifact) => String](prefixed("artifact-base-name"), "Function that produces the JavaFX artifact name (without file extension) from its definition.") 92 | val artifactBaseNameValue = SettingKey[String](prefixed("artifact-base-name-value"), "The actual name of the JavaFX artifact (without file extension).") 93 | 94 | val template = SettingKey[Template](prefixed("template"), "JavaFX HTML template settings.") 95 | 96 | val templateFile = SettingKey[Option[String]](prefixed("template-file"), "HTML template input file.") 97 | val templateDestFile = SettingKey[Option[String]](prefixed("template-dest-file"), "HTML template output file.") 98 | val placeholderId = SettingKey[String](prefixed("placeholder-id"), "HTML template placeholder id.") 99 | 100 | val info = SettingKey[Info](prefixed("info"), "Application info settings") 101 | 102 | val vendor = SettingKey[String](prefixed("vendor"), "Application vendor") 103 | val title = SettingKey[String](prefixed("title"), "Application title") 104 | val appVersion = SettingKey[String](prefixed("app-version"), "Application version specifier used in launcher and installer") 105 | val category = SettingKey[String](prefixed("category"), "Application category") 106 | val description = SettingKey[String](prefixed("description"), "Application description") 107 | val copyright = SettingKey[String](prefixed("copyright"), "Application copyright") 108 | val license = SettingKey[String](prefixed("license"), "Application license") 109 | 110 | val dimensions = SettingKey[Dimensions](prefixed("dimensions"), "JavaFX dimensions settings.") 111 | 112 | val width = SettingKey[Int](prefixed("width"), "JavaFX application width.") 113 | val height = SettingKey[Int](prefixed("height"), "JavaFX application height.") 114 | val embeddedWidth = SettingKey[String](prefixed("embedded-width"), "JavaFX applet width.") 115 | val embeddedHeight = SettingKey[String](prefixed("embedded-height"), "JavaFX applet height.") 116 | 117 | val permissions = SettingKey[Permissions](prefixed("permissions"), "JavaFX application permission settings.") 118 | 119 | val elevated = SettingKey[Boolean](prefixed("elevated"), "Whether this JavaFX application requires elevated permissions.") 120 | val cacheCertificates = SettingKey[Boolean](prefixed("cache-certificates"), "Whether the signing certificates should be cached in the deployment descriptor.") 121 | 122 | val signing = SettingKey[Signing](prefixed("signing"), "Settings for JavaFX jar signing.") 123 | 124 | val keyStore = SettingKey[Option[File]](prefixed("keystore"), "Filename for keystore for jar signing.") 125 | val storePass = SettingKey[Option[String]](prefixed("storepass"), "Password for keystore for jar signing.") 126 | val alias = SettingKey[Option[String]](prefixed("alias"), "Key name for jar signing.") 127 | val keyPass = SettingKey[Option[String]](prefixed("keypass"), "Key password for jar signing.") 128 | val storeType = SettingKey[Option[String]](prefixed("storetype"), "Keystore type for signing.") 129 | 130 | val misc = SettingKey[Misc](prefixed("misc"), "Misc JavaFX settings.") 131 | 132 | val cssToBin = SettingKey[Boolean](prefixed("css-to-bin"), "Convert CSS files to binary.") 133 | val verbose = SettingKey[Boolean](prefixed("verbose"), "Sets verbose flag in fx:deploy task (output currently swallowed by sbt).") 134 | 135 | val platform = SettingKey[Platform](prefixed("platform"), "JavaFX platform settings.") 136 | 137 | val javafx = SettingKey[Option[String]](prefixed("javafx"), "Required JavaFX version.") 138 | val j2se = SettingKey[Option[String]](prefixed("j2se"), "Required JRE version.") 139 | val jvmargs = SettingKey[Seq[String]](prefixed("jvmargs"), "JVM options.") 140 | val jvmuserargs = SettingKey[Seq[(String, String)]](prefixed("jvmuserargs"), "User overridable JVM options.") 141 | val properties = SettingKey[Seq[(String, String)]](prefixed("properties"), "JVM properties.") 142 | 143 | val transformXml = SettingKey[Elem => Elem](prefixed("transform-xml"), "Optionally transformation of the intermediate build XML before packaging (advanced).") 144 | val postProcess = SettingKey[File => Unit](prefixed("post-process"), "Optionally post-processing of the packaged artifact.") 145 | 146 | val prepareBuild = TaskKey[Unit](prefixed("prepare-build"), "Prepares JavaFX packaging without running the Ant build file.") 147 | val runBuild = TaskKey[Unit](prefixed("run-build"), "Completes JavaFX packaging by running an already prepared Ant build file.") 148 | val packageJavaFx = TaskKey[Unit]("package-javafx", "Packages a JavaFX application.") 149 | 150 | 151 | // Some convenience methods 152 | 153 | def jdk(s: String) = Some(JDK(s)) 154 | def sdk(s: String) = Some(SDK(s)) 155 | } 156 | 157 | // Define the tasks 158 | 159 | val prepareBuildTask = (jfx, name, classDirectory in Compile, fullClasspath in Runtime, baseDirectory, crossTarget, packageOptions in JFX.packageJavaFx) map { 160 | (jfx, name, classDir, fullClasspath, baseDirectory, crossTarget, packOptions) => 161 | 162 | // Check that the JavaFX Ant library is present 163 | 164 | val antLib = jfx.paths.antLib getOrElse sys.error("Path to ant-javafx.jar not defined.") 165 | 166 | if (!file(antLib).exists) sys.error(antLib + " does not exist.") 167 | 168 | // Setup paths and delete anything left over from previous build 169 | 170 | import IO._ 171 | 172 | val pkgResourcesDir = jfx.paths.pkgResourcesDir 173 | 174 | val jarDir = crossTarget 175 | val libDir = crossTarget / "lib" 176 | val distDir = crossTarget / jfx.output.artifactBaseNameValue 177 | 178 | val jarFile = jarDir / (jfx.output.artifactBaseNameValue + ".jar") 179 | 180 | delete(libDir) 181 | delete(distDir) 182 | 183 | if (distDir.exists && distDir.list.nonEmpty) 184 | sys.error("Could not delete previous build. Make sure no files are open in " + distDir) 185 | 186 | val templateFile = jfx.template.file map { f => 187 | if (file(f).isAbsolute) file(f) 188 | else (baseDirectory / f) 189 | } 190 | 191 | val templateDestFile = jfx.template.destFile orElse jfx.template.file map { f => 192 | if (file(f).isAbsolute) file(f) 193 | else (distDir / f) 194 | } 195 | 196 | // All library jars that should be packaged with the application 197 | 198 | val libJars = fullClasspath map (_.data) filter ClasspathUtilities.isArchive filterNot (_.getName endsWith "jfxrt.jar") 199 | 200 | // Copy the jars to temporary lib folder 201 | 202 | val srcToDest = libJars map (src => (src, libDir / src.getName)) 203 | 204 | copy(srcToDest) 205 | 206 | val appVersion = jfx.info.appVersion 207 | 208 | // Convert manifest attributes in packageOption, scoped to this task, to xml 209 | 210 | import collection.JavaConversions._ 211 | val manifestAttributes = packOptions.collect { 212 | case attributes: ManifestAttributes => attributes.attributes.map { case (key, value) => (key.toString, value) } 213 | case JarManifest(manifest) => 214 | (manifest.getMainAttributes.entrySet map (entry => (entry.getKey.toString, entry.getValue.toString))).toList 215 | }.flatten 216 | 217 | val manifestAttributeXmls = manifestAttributes map { case (key, value) => } 218 | 219 | // Generate the Ant buildfile 220 | 221 | val antBuildXml = 222 | 223 | 224 | 225 | { 226 | if (jfx.misc.cssToBin) { 227 | 228 | 229 | 230 | 231 | 232 | 233 | } 234 | } 235 | 236 | 237 | { 238 | jfx.misc.platform.jvmargs map { value => 239 | 240 | } 241 | } 242 | { 243 | jfx.misc.platform.jvmuserargs map { 244 | case (name, value) => 245 | 246 | } 247 | } 248 | { 249 | jfx.misc.platform.properties map { 250 | case (name, value) => 251 | 252 | } 253 | } 254 | 255 | 256 | 257 | 258 | 259 | 260 | { if (libJars.nonEmpty) } 261 | 262 | { if (manifestAttributeXmls.nonEmpty) { manifestAttributeXmls } } 263 | 264 | { 265 | if (jfx.permissions.elevated) { 266 | 267 | 268 | 269 | } 270 | } 271 | { 272 | if (jfx.permissions.elevated && libJars.nonEmpty) { 273 | 274 | 275 | 276 | } 277 | } 278 | 279 | 280 | 281 | 282 | 283 | 284 | { if (libJars.nonEmpty) } 285 | 286 | 287 | { 288 | if (templateFile.isDefined) { 289 | val tf = templateFile.get 290 | 291 | } 292 | } 293 | 294 | 295 | 296 | 297 | val buildFile = crossTarget / "build.xml" 298 | 299 | // Optionally transform the build XML, then write it to file 300 | 301 | write(buildFile, jfx.misc.transformXml(antBuildXml).toString) 302 | } 303 | 304 | val runBuildTask = (jfx, crossTarget) map { (jfx, crossTarget) => 305 | 306 | val buildFile = crossTarget / "build.xml" 307 | val distDir = crossTarget / jfx.output.artifactBaseNameValue 308 | 309 | // Run the buildfile 310 | 311 | val antProject = new ant.Project 312 | 313 | antProject setUserProperty ("ant.file", buildFile.getAbsolutePath) 314 | antProject init () 315 | 316 | val helper = ant.ProjectHelper.getProjectHelper 317 | helper parse (antProject, buildFile) 318 | 319 | println("Packaging to " + distDir + "...") 320 | 321 | antProject executeTarget "default" 322 | 323 | jfx.misc.postProcess(distDir) 324 | } 325 | 326 | val packageJavaFxTask = (JFX.prepareBuild, JFX.runBuild) { (prepare, run) => prepare doFinally run } 327 | 328 | // Settings that are automatically loaded (as defaults) 329 | 330 | override val settings = Seq( 331 | JFX.devKit := JFX.jdk(System.getProperty("java.home") + "/.."), 332 | JFX.jfxrt <<= JFX.devKit(_ map DevKit.jfxrt), 333 | JFX.antLib <<= JFX.devKit(_ map DevKit.antLib), 334 | JFX.pkgResourcesDir <<= baseDirectory(d => (d / "src/deploy").getAbsolutePath), 335 | JFX.paths <<= (JFX.devKit, JFX.jfxrt, JFX.antLib, JFX.pkgResourcesDir) apply Paths.apply, 336 | JFX.addJfxrtToClasspath <<= JFX.devKit(_ map (devKit => !DevKit.isJdk(devKit)) getOrElse false), 337 | JFX.mainClass := None, 338 | JFX.javaOnly := false, 339 | JFX.nativeBundles := "none", 340 | JFX.artifactBaseName <<= crossPaths(p => (v, id, a) => List(Some(a.name), if (p) Some("_" + v) else None, Some("-" + id.revision)).flatten.mkString), 341 | JFX.artifactBaseNameValue <<= (scalaVersion, projectID, artifact, JFX.artifactBaseName) apply { (v, id, a, f) => f(v, id, a) }, 342 | JFX.output <<= (JFX.nativeBundles, JFX.artifactBaseName, JFX.artifactBaseNameValue) apply Output.apply, 343 | JFX.templateFile := None, 344 | JFX.templateDestFile := None, 345 | JFX.placeholderId := "javafx", 346 | JFX.template <<= (JFX.templateFile, JFX.templateDestFile, JFX.placeholderId) apply Template.apply, 347 | JFX.width := 800, 348 | JFX.height := 600, 349 | JFX.embeddedWidth := "100%", 350 | JFX.embeddedHeight := "100%", 351 | JFX.dimensions <<= (JFX.width, JFX.height, JFX.embeddedWidth, JFX.embeddedHeight) apply Dimensions.apply, 352 | JFX.elevated := false, 353 | JFX.cacheCertificates := false, 354 | JFX.permissions <<= (JFX.elevated, JFX.cacheCertificates) apply { Permissions(_, _) }, 355 | JFX.vendor := "Unknown", 356 | JFX.title <<= name, 357 | JFX.appVersion <<= version, 358 | JFX.category := "", 359 | JFX.description := "", 360 | JFX.copyright := "", 361 | JFX.license := "", 362 | JFX.info <<= (JFX.vendor, JFX.title, JFX.appVersion, JFX.category, JFX.copyright, JFX.description, JFX.license) apply Info.apply, 363 | JFX.keyStore := None, 364 | JFX.storePass := None, 365 | JFX.alias := None, 366 | JFX.keyPass := None, 367 | JFX.storeType := None, 368 | JFX.signing <<= (JFX.keyStore, JFX.storePass, JFX.alias, JFX.keyPass, JFX.storeType) apply Signing.apply, 369 | JFX.javafx := None, 370 | JFX.j2se := None, 371 | JFX.jvmargs := Nil, 372 | JFX.jvmuserargs := Nil, 373 | JFX.properties := Nil, 374 | JFX.platform <<= (JFX.javafx, JFX.j2se, JFX.jvmargs, JFX.jvmuserargs, JFX.properties) apply Platform.apply, 375 | JFX.cssToBin := false, 376 | JFX.verbose := false, 377 | JFX.transformXml := identity, 378 | JFX.postProcess := { _ => }, 379 | JFX.misc <<= (JFX.platform, JFX.cssToBin, JFX.verbose, JFX.transformXml, JFX.postProcess) apply Misc.apply) 380 | 381 | // Settings that must be manually loaded 382 | 383 | val jfxSettings = Seq( 384 | mainClass in (Compile, run) <<= JFX.mainClass map (x => x), 385 | (unmanagedClasspath in Compile) <<= (unmanagedClasspath in Compile, JFX.addJfxrtToClasspath, JFX.jfxrt) map { (cp, add, jfxrt) => if (add) cp :+ Attributed.blank(file(jfxrt getOrElse sys.error("Path to jfxrt.jar not defined."))) else cp }, 386 | (unmanagedClasspath in Runtime) <<= (unmanagedClasspath in Runtime, JFX.addJfxrtToClasspath, JFX.jfxrt) map { (cp, add, jfxrt) => if (add) cp :+ Attributed.blank(file(jfxrt getOrElse sys.error("Path to jfxrt.jar not defined."))) else cp }, 387 | (unmanagedClasspath in Test) <<= (unmanagedClasspath in Test, JFX.addJfxrtToClasspath, JFX.jfxrt) map { (cp, add, jfxrt) => if (add) cp :+ Attributed.blank(file(jfxrt getOrElse sys.error("Path to jfxrt.jar not defined."))) else cp }, 388 | autoScalaLibrary <<= JFX.javaOnly(x => !x), 389 | crossPaths <<= JFX.javaOnly(x => !x), 390 | fork in run := true, 391 | JFX.prepareBuild <<= prepareBuildTask, 392 | JFX.runBuild <<= runBuildTask, 393 | JFX.packageJavaFx <<= packageJavaFxTask, 394 | jfx <<= (JFX.paths, JFX.mainClass, JFX.output, JFX.template, JFX.dimensions, JFX.permissions, JFX.info, JFX.signing, JFX.misc) apply { new JFX(_, _, _, _, _, _, _, _, _) }) 395 | } 396 | --------------------------------------------------------------------------------