├── .github
└── issue_template.md
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── docs
├── dmg-properties-explained.png
├── gradle
│ └── plugin-configuration-samples.md
├── linux-specific-properties.md
├── macosx-specific-properties.md
├── manifest.md
├── maven
│ └── plugin-configuration-samples.md
├── windows-specific-properties.md
└── windows-tools-guide.md
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── it
├── settings.xml
└── simple-it
│ ├── pom.xml
│ └── verify.groovy
└── main
├── java
├── io
│ └── github
│ │ └── fvarrui
│ │ └── javapackager
│ │ ├── gradle
│ │ ├── AbstractPackageTask.java
│ │ ├── CopyDependencies.java
│ │ ├── CreateRunnableJar.java
│ │ ├── CreateTarball.java
│ │ ├── CreateWindowsExeLaunch4j.java
│ │ ├── CreateZipball.java
│ │ ├── GradleContext.java
│ │ ├── PackagePlugin.java
│ │ ├── PackagePluginExtension.java
│ │ └── PackageTask.java
│ │ ├── maven
│ │ ├── CopyDependencies.java
│ │ ├── CreateRunnableJar.java
│ │ ├── CreateTarball.java
│ │ ├── CreateWindowsExeLaunch4j.java
│ │ ├── CreateZipball.java
│ │ ├── MavenContext.java
│ │ ├── PackageMojo.java
│ │ └── ResolveLicenseFromPOM.java
│ │ ├── model
│ │ ├── Arch.java
│ │ ├── CFBundlePackageType.java
│ │ ├── FileAssociation.java
│ │ ├── HeaderType.java
│ │ ├── InfoPlist.java
│ │ ├── LinuxConfig.java
│ │ ├── MacConfig.java
│ │ ├── MacStartup.java
│ │ ├── Manifest.java
│ │ ├── ManifestSection.java
│ │ ├── Platform.java
│ │ ├── Registry.java
│ │ ├── RegistryEntry.java
│ │ ├── Scripts.java
│ │ ├── SetupMode.java
│ │ ├── Template.java
│ │ ├── ValueType.java
│ │ ├── WindowsConfig.java
│ │ ├── WindowsExeCreationTool.java
│ │ └── WindowsSigning.java
│ │ ├── packagers
│ │ ├── AbstractCreateWindowsExe.java
│ │ ├── ArtifactGenerator.java
│ │ ├── BundleJre.java
│ │ ├── Context.java
│ │ ├── CreateWindowsExeWhy.java
│ │ ├── CreateWindowsExeWinRun4j.java
│ │ ├── GenerateAppImage.java
│ │ ├── GenerateDeb.java
│ │ ├── GenerateDmg.java
│ │ ├── GenerateMsi.java
│ │ ├── GenerateMsm.java
│ │ ├── GeneratePkg.java
│ │ ├── GenerateRpm.java
│ │ ├── GenerateSetup.java
│ │ ├── LinuxPackager.java
│ │ ├── MacPackager.java
│ │ ├── Packager.java
│ │ ├── PackagerFactory.java
│ │ ├── PackagerSettings.java
│ │ └── WindowsPackager.java
│ │ └── utils
│ │ ├── CharsetUtil.java
│ │ ├── CommandUtils.java
│ │ ├── Commandline.java
│ │ ├── ExecutionResult.java
│ │ ├── FileUtils.java
│ │ ├── IconUtils.java
│ │ ├── JDKUtils.java
│ │ ├── JarUtils.java
│ │ ├── Logger.java
│ │ ├── MojoExecutorUtils.java
│ │ ├── ObjectUtils.java
│ │ ├── RcEdit.java
│ │ ├── StringUtils.java
│ │ ├── ThreadUtils.java
│ │ ├── VelocityUtils.java
│ │ ├── VersionUtils.java
│ │ └── XMLUtils.java
└── net
│ └── jsign
│ └── WindowsSigner.java
└── resources
├── linux
├── assembly.xml.vtl
├── control.vtl
├── default-icon.png
├── desktop-appimage.vtl
├── desktop.vtl
├── mime.xml.vtl
└── startup.sh.vtl
├── mac
├── Info.plist.vtl
├── RuntimeInfo.plist.vtl
├── assembly.xml.vtl
├── background.png
├── customize-dmg.applescript.vtl
├── default-icon.icns
├── entitlements.plist.vtl
├── startup.vtl
├── universalJavaApplicationStub
├── universalJavaApplicationStub.arm64
├── universalJavaApplicationStub.sh
└── universalJavaApplicationStub.x86_64
└── windows
├── JavaLauncher.exe
├── WinRun4J.exe
├── WinRun4J64.exe
├── assembly.xml.vtl
├── default-icon.ico
├── exe.manifest.vtl
├── ini.vtl
├── iss.vtl
├── msm.wxs.vtl
├── rcedit-x64.exe
├── startup.vbs.vtl
├── why-ini.vtl
└── wxs.vtl
/.github/issue_template.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javapackager/JavaPackager/94db2a7974b3f9b8a11f2be280ff5472391a2e24/.github/issue_template.md
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | **/build/
3 |
4 | # Package Files #
5 | bin
6 | target
7 | .settings/
8 | .classpath
9 | .project
10 |
11 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
12 | !gradle-wrapper.jar
13 | src/main/resources/windows/winrun4j-launcher.jar
14 |
15 | # Log file
16 | *.log
17 |
18 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
19 | hs_err_pid*
20 |
21 | # IntelliJ
22 | **/.idea/
23 | **.iml
24 |
25 | # Eclipse
26 | **/.settings/
27 |
28 | # Maven
29 | **/target/
30 | **/*.xml.releaseBackup
31 | /release.properties
32 |
33 | ## More
34 | .DS_Store
35 |
--------------------------------------------------------------------------------
/docs/dmg-properties-explained.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javapackager/JavaPackager/94db2a7974b3f9b8a11f2be280ff5472391a2e24/docs/dmg-properties-explained.png
--------------------------------------------------------------------------------
/docs/gradle/plugin-configuration-samples.md:
--------------------------------------------------------------------------------
1 | # Plugin configuration samples for Gradle
2 |
3 | ## Minimal config
4 |
5 | > :warning: This minimal configuration will not bundle a JRE, so final user will need one in order to run the app.
6 |
7 | ### Using your own task
8 |
9 | Add next task to your `build.gradle` file:
10 |
11 | ```groovy
12 | task packageMyApp(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
13 | mainClass = 'fvarrui.sample.Main'
14 | }
15 | ```
16 |
17 | And run `gradle packageMyApp`.
18 |
19 | ### Using default task
20 |
21 | Default `package` task is configured using `javapackager` extension so, add next to your `build.gradle` file:
22 |
23 | ```groovy
24 | javapackager {
25 | mainClass = 'fvarrio.sample.Main'
26 | }
27 | ```
28 | And run `gradle package`.
29 |
30 | ## Bundle with a customized JRE
31 |
32 | ```groovy
33 | task packageMyApp(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
34 | mainClass = 'fvarrui.sample.Main'
35 | bundleJre = true
36 | }
37 | ```
38 |
39 | > `customizedJre` is `true` by default, so you don't have to specify it.
40 |
41 | ## Bundle with a full JRE
42 |
43 | ```groovy
44 | task packageMyApp(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
45 | mainClass = 'fvarrui.sample.Main'
46 | bundleJre = true
47 | customizedJre = false
48 | }
49 | ```
50 |
51 | ## Bundle with an existing JRE
52 |
53 | ```groovy
54 | task packageMyApp(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
55 | mainClass = 'fvarrui.sample.Main'
56 | bundleJre = true
57 | jrePath = file('C:\Program Files\Java\jre1.8.0_231')
58 | }
59 | ```
60 |
61 | ## Bundle your own fat JAR
62 |
63 | ```groovy
64 | task packageMyApp(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
65 | mainClass = 'fvarrui.sample.Main'
66 | bundleJre = true
67 | runnableJar = file('path/to/your/own/fat.jar')
68 | copyDependencies = false
69 | }
70 | ```
71 |
72 | ## Multiple executions
73 |
74 | ```groovy
75 | javapackager {
76 | // common configuration
77 | mainClass = 'fvarrui.sample.Main'
78 | }
79 | task packageMyAppWithJRE(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
80 | name = 'Sample'
81 | bundleJre = true
82 | }
83 | task packageMyAppWithoutJRE(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
84 | name = 'Sample-nojre'
85 | bundleJre = false
86 | }
87 | task packageMyApp(dependsOn: [ 'packageMyAppWithJRE', 'packageMyAppWithoutJRE' ])
88 | ```
89 |
90 | E.g. on Windows, last configuration will generate next artifacts:
91 | * `Sample_x.y.z.exe` with a bundled JRE.
92 | * `Sample-nojre_x.y.z.exe` without JRE.
93 |
94 | ## Bundling for multiple platforms
95 |
96 | ```groovy
97 | javapackager {
98 | // common configuration
99 | mainClass = 'fvarrui.sample.Main'
100 | bundleJre = true
101 | generateInstaller = false
102 | }
103 | task packageMyAppForLinux(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
104 | platform = linux
105 | createTarball = true
106 | jdkPath = file('X:\\path\to\linux\jdk')
107 | }
108 | task packageMyAppForMac(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
109 | platform = mac
110 | createTarball = true
111 | jdkPath = file('X:\\path\to\mac\jdk')
112 | }
113 | task packageMyAppForWindows(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: build) {
114 | platform = windows
115 | createZipball = true
116 | }
117 | task packageMyApp(dependsOn: [ 'packageMyAppForLinux', 'packageMyAppForMac', 'packageMyAppForWindows' ])
118 | ```
119 |
120 | E.g. on Windows, running `packageMyApp` task will generate next artifacts:
121 |
122 | * `${name}_${version}-linux.tar.gz` with the GNU/Linux application including a customized JRE.
123 | * `${name}_${version}-mac.tar.gz` with the MacOS application including a customized JRE.
124 | * `${name}_${version}-windows.zip` with the Windows application including a customized JRE.
125 |
126 | As last sample is running on Windows, it's not necessary to specify a JDK when bundling for Windows (it uses current JDK by default). Otherwise, if running on GNU/Linux or MacOS, you have to specify a JDK for Windows.
127 |
--------------------------------------------------------------------------------
/docs/linux-specific-properties.md:
--------------------------------------------------------------------------------
1 | # GNU/Linux specific properties
2 |
3 | ```xml
4 |
5 | path/to/icon.png
6 | true|false
7 | true|false
8 | true|false
9 | true|false
10 |
11 | Utility
12 | ...
13 |
14 |
15 | ```
16 |
17 | | Property | Mandatory | Default value | Description |
18 | | ------------------ | --------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------- |
19 | | `pngFile` | :x: | `null` | Icon file. |
20 | | `generateAppImage` | :x: | `true` | [AppImage](https://appimage.org/) package will be generated. |
21 | | `generateDeb` | :x: | `true` | DEB package will be generated. |
22 | | `generateRpm` | :x: | `true` | RPM package will be generated. |
23 | | `wrapJar` | :x: | `true` | Wraps JAR file inside the executable if `true`. |
24 | | `categories` | :x: | `[ "Utility"]` | [Main categories](https://specifications.freedesktop.org/menu-spec/latest/apa.html) in the application's desktop entry file. |
25 |
--------------------------------------------------------------------------------
/docs/manifest.md:
--------------------------------------------------------------------------------
1 | # *manifest* property
2 |
3 | `manifest` property allows adding additional manifest entries and sections.
4 |
5 | ## Maven
6 |
7 | ```xml
8 |
9 |
10 | Peter
11 |
12 |
13 |
14 | foo/
15 |
16 | foo1
17 |
18 |
19 |
20 |
21 | ```
22 |
23 | ## Gradle
24 |
25 | ```groovy
26 | manifest {
27 | additionalEntries = [
28 | 'Created-By': 'Peter'
29 | ]
30 | sections = [
31 | new io.github.fvarrui.javapackager.model.ManifestSection ([
32 | name: "foo/",
33 | entries: [
34 | 'Implementation-Version': 'foo1'
35 | ]
36 | ])
37 | ]
38 | }
39 | ```
40 |
41 | ## Result
42 |
43 | Both produce the following `MANIFEST.MF` file:
44 |
45 | ```properties
46 | Manifest-Version: 1.0
47 | Created-By: Peter
48 |
49 | Name: foo/
50 | Implementation-Version: foo1
51 | ```
52 |
--------------------------------------------------------------------------------
/docs/windows-tools-guide.md:
--------------------------------------------------------------------------------
1 | # Windows tools installation guide
2 |
3 | As explained in the [docs](https://github.com/fvarrui/JavaPackager#generated-artifacts), you must install [Inno Setup (iscc)](https://jrsoftware.org/isinfo.php) to generate an EXE installer and [WIX Toolset (candle and light)](https://wixtoolset.org/) to generate an MSI file.
4 |
5 | For Inno Setup 5.x, the Unicode version should be used, because the scripts that JavaPacker will be creating as an input will be UTF-8 encoded.
6 |
7 | ## Using Chocolatey
8 | You can install both tools in a simple way using [Chocolatey](https://chocolatey.org/) package manager:
9 |
10 | 1. [Install Chocolatey](https://chocolatey.org/install)
11 | 2. Run next command on CMD or PowerShell as Administrator to install both tools:
12 |
13 | ```
14 | choco install -y innosetup wixtoolset
15 | ```
16 |
17 | > And both tools will be automatically available in `PATH`.
18 |
19 | ## Using scoop
20 | You can also use [Scoop](https://github.com/ScoopInstaller/Scoop/wiki) to achieve the same goal. Scoop is a lightweight alternative to Chocolatey that doesn't require admin rights and installs by default to a folder in the user's home directory.
21 |
22 | 1. [Install Scoop](https://scoop.sh/)
23 | 2. Run in CMD or PowerShell (no need to be Administrator):
24 |
25 | ```
26 | scoop bucket add extras
27 | scoop install inno-setup
28 | scoop install wixtoolset
29 | ```
30 |
31 | > Both tools will also be available in `PATH`.
32 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javapackager/JavaPackager/94db2a7974b3f9b8a11f2be280ff5472391a2e24/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'javapackager'
--------------------------------------------------------------------------------
/src/it/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
15 |
16 |
17 | it-repo
18 |
19 | true
20 |
21 |
22 |
23 | local.central
24 | @localRepositoryUrl@
25 |
26 | true
27 |
28 |
29 | true
30 |
31 |
32 |
33 |
34 |
35 | local.central
36 | @localRepositoryUrl@
37 |
38 | true
39 |
40 |
41 | true
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/it/simple-it/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | fvarrui.maven.it
7 | simple-it
8 | 1.0-SNAPSHOT
9 |
10 | A simple IT verifying the basic use case.
11 |
12 |
13 | UTF-8
14 |
15 |
16 |
17 |
18 |
19 | @project.groupId@
20 | @project.artifactId@
21 | @project.version@
22 |
23 |
24 | touch
25 | validate
26 |
27 | touch
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/it/simple-it/verify.groovy:
--------------------------------------------------------------------------------
1 | File touchFile = new File( basedir, "target/touch.txt" );
2 |
3 | assert touchFile.isFile()
4 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/gradle/AbstractPackageTask.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.gradle;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | import org.gradle.api.DefaultTask;
8 | import org.gradle.api.tasks.OutputFiles;
9 | import org.gradle.api.tasks.TaskAction;
10 |
11 | import io.github.fvarrui.javapackager.packagers.Packager;
12 |
13 | /**
14 | * Abstract packaging task for Gradle
15 | */
16 | public abstract class AbstractPackageTask extends DefaultTask {
17 |
18 | private List outputFiles;
19 |
20 | @OutputFiles
21 | public List getOutputFiles() {
22 | return outputFiles != null ? outputFiles : new ArrayList<>();
23 | }
24 |
25 | /**
26 | * Task constructor
27 | */
28 | public AbstractPackageTask() {
29 | super();
30 | setGroup(PackagePlugin.GROUP_NAME);
31 | setDescription("Packages the application as a native Windows, MacOS or GNU/Linux executable and creates an installer");
32 | getOutputs().upToDateWhen(o -> false);
33 | }
34 |
35 | /**
36 | * Packaging task action
37 | * @throws Exception Throwed if something went wrong
38 | */
39 | @TaskAction
40 | public void doPackage() throws Exception {
41 |
42 | Packager packager = createPackager();
43 |
44 | // generates app, installers and bundles
45 | File app = packager.createApp();
46 | List installers = packager.generateInstallers();
47 | List bundles = packager.createBundles();
48 |
49 | // sets generated files as output
50 | outputFiles = new ArrayList<>();
51 | outputFiles.add(app);
52 | outputFiles.addAll(installers);
53 | outputFiles.addAll(bundles);
54 |
55 | }
56 |
57 | /**
58 | * Creates a platform specific packager
59 | * @return Packager
60 | * @throws Exception Throwed if something went wrong
61 | */
62 | protected abstract Packager createPackager() throws Exception;
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/gradle/CopyDependencies.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.gradle;
2 |
3 | import java.io.File;
4 |
5 | import org.gradle.api.Project;
6 | import org.gradle.api.tasks.Copy;
7 |
8 | import io.github.fvarrui.javapackager.packagers.ArtifactGenerator;
9 | import io.github.fvarrui.javapackager.packagers.Context;
10 | import io.github.fvarrui.javapackager.packagers.Packager;
11 |
12 | /**
13 | * Copies all dependencies to app folder on Gradle context
14 | */
15 | public class CopyDependencies extends ArtifactGenerator {
16 |
17 | public Copy copyLibsTask;
18 |
19 | public CopyDependencies() {
20 | super("Libs folder");
21 | }
22 |
23 | @Override
24 | public boolean skip(Packager packager) {
25 | return !packager.getCopyDependencies();
26 | }
27 |
28 | @Override
29 | protected File doApply(Packager packager) {
30 |
31 | File libsFolder = new File(packager.getJarFileDestinationFolder(), "libs");
32 | Project project = Context.getGradleContext().getProject();
33 |
34 | copyLibsTask = (Copy) project.getTasks().findByName("copyLibs");
35 | if (copyLibsTask == null) {
36 | copyLibsTask = project.getTasks().create("copyLibs", Copy.class);
37 | }
38 | copyLibsTask.setDuplicatesStrategy(Context.getGradleContext().getDuplicatesStrategy());
39 | copyLibsTask.from(project.getConfigurations().getByName("runtimeClasspath"));
40 | copyLibsTask.into(project.file(libsFolder));
41 | copyLibsTask.getActions().forEach(action -> action.execute(copyLibsTask));
42 |
43 | return libsFolder;
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/gradle/CreateRunnableJar.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.gradle;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.Arrays;
6 | import java.util.List;
7 | import java.util.stream.Collectors;
8 |
9 | import org.apache.commons.lang3.StringUtils;
10 | import org.gradle.api.Project;
11 | import org.gradle.api.tasks.bundling.Jar;
12 |
13 | import io.github.fvarrui.javapackager.model.Manifest;
14 | import io.github.fvarrui.javapackager.packagers.ArtifactGenerator;
15 | import io.github.fvarrui.javapackager.packagers.Context;
16 | import io.github.fvarrui.javapackager.packagers.Packager;
17 |
18 | /**
19 | * Creates a runnable jar file from sources on Maven context
20 | */
21 | public class CreateRunnableJar extends ArtifactGenerator {
22 |
23 | public CreateRunnableJar() {
24 | super("Runnable JAR");
25 | }
26 |
27 | @Override
28 | protected File doApply(Packager packager) {
29 |
30 | String classifier = "runnable";
31 | String name = packager.getName();
32 | String version = packager.getVersion();
33 | String mainClass = packager.getMainClass();
34 | File outputDirectory = packager.getOutputDirectory();
35 | Project project = Context.getGradleContext().getProject();
36 | File libsFolder = packager.getLibsFolder();
37 | Manifest manifest = packager.getManifest();
38 |
39 | List dependencies = new ArrayList<>();
40 | if (libsFolder != null && libsFolder.exists()) {
41 | dependencies = Arrays.asList(libsFolder.listFiles()).stream().map(f -> libsFolder.getName() + "/" + f.getName()).collect(Collectors.toList());
42 | }
43 |
44 | Jar jarTask = (Jar) project.getTasks().findByName("jar");
45 | jarTask.setProperty("archiveBaseName", name);
46 | jarTask.setProperty("archiveVersion", version);
47 | jarTask.setProperty("archiveClassifier", classifier);
48 | jarTask.setProperty("destinationDirectory", outputDirectory);
49 | jarTask.getManifest().getAttributes().put("Created-By", "Gradle " + Context.getGradleContext().getProject().getGradle().getGradleVersion());
50 | jarTask.getManifest().getAttributes().put("Built-By", System.getProperty("user.name"));
51 | jarTask.getManifest().getAttributes().put("Build-Jdk", System.getProperty("java.version"));
52 | jarTask.getManifest().getAttributes().put("Class-Path", StringUtils.join(dependencies, " "));
53 | jarTask.getManifest().getAttributes().put("Main-Class", mainClass);
54 | if (manifest != null) {
55 | jarTask.getManifest().attributes(manifest.getAdditionalEntries());
56 | manifest.getSections().stream().forEach(s -> jarTask.getManifest().attributes(s.getEntries(), s.getName()));
57 | }
58 |
59 | jarTask.getActions().forEach(action -> action.execute(jarTask));
60 |
61 | return jarTask.getArchiveFile().get().getAsFile();
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/gradle/CreateTarball.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.gradle;
2 |
3 | import java.io.File;
4 | import java.util.UUID;
5 |
6 | import org.gradle.api.tasks.bundling.Compression;
7 | import org.gradle.api.tasks.bundling.Tar;
8 |
9 | import io.github.fvarrui.javapackager.model.Platform;
10 | import io.github.fvarrui.javapackager.packagers.ArtifactGenerator;
11 | import io.github.fvarrui.javapackager.packagers.Context;
12 | import io.github.fvarrui.javapackager.packagers.MacPackager;
13 | import io.github.fvarrui.javapackager.packagers.Packager;
14 |
15 | /**
16 | * Creates tarball (tar.gz file) on Gradle context
17 | */
18 | public class CreateTarball extends ArtifactGenerator {
19 |
20 | public CreateTarball() {
21 | super("Tarball");
22 | }
23 |
24 | @Override
25 | public boolean skip(Packager packager) {
26 | return !packager.getCreateTarball();
27 | }
28 |
29 | @Override
30 | protected File doApply(Packager packager) throws Exception {
31 |
32 | String name = packager.getName();
33 | String version = packager.getVersion();
34 | Platform platform = packager.getPlatform();
35 | File outputDirectory = packager.getOutputDirectory();
36 | File appFolder = packager.getAppFolder();
37 | File executable = packager.getExecutable();
38 | String jreDirectoryName = packager.getJreDirectoryName();
39 |
40 | // tgz file name
41 | String finalName = packager.getTarballName() != null ? packager.getTarballName() : name + "-" + version + "-" + platform;
42 | String format = ".tar.gz";
43 | File tarFile = new File(outputDirectory, finalName + format);
44 |
45 | Tar tarTask = createTarTask();
46 | tarTask.setProperty("archiveFileName", tarFile.getName());
47 | tarTask.setProperty("destinationDirectory", outputDirectory);
48 | tarTask.setCompression(Compression.GZIP);
49 |
50 | // if zipball is for windows platform
51 | if (Platform.windows.equals(platform)) {
52 |
53 | tarTask.from(appFolder.getParentFile(), copySpec -> {
54 | copySpec.include(appFolder.getName() + "/**");
55 | });
56 |
57 | }
58 |
59 | // if zipball is for linux platform
60 | else if (Platform.linux.equals(platform)) {
61 |
62 | tarTask.from(appFolder.getParentFile(), copySpec -> {
63 | copySpec.include(appFolder.getName() + "/**");
64 | copySpec.exclude(appFolder.getName() + "/" + executable.getName());
65 | copySpec.exclude(appFolder.getName() + "/" + jreDirectoryName + "/bin/*");
66 | copySpec.exclude(appFolder.getName() + "/scripts/*");
67 | });
68 | tarTask.from(appFolder.getParentFile(), copySpec -> {
69 | copySpec.include(appFolder.getName() + "/" + executable.getName());
70 | copySpec.include(appFolder.getName() + "/" + jreDirectoryName + "/bin/*");
71 | copySpec.include(appFolder.getName() + "/scripts/*");
72 | copySpec.setFileMode(0755);
73 | });
74 |
75 | }
76 |
77 | // if zipball is for macos platform
78 | else if (Platform.mac.equals(platform)) {
79 |
80 | MacPackager macPackager = (MacPackager) packager;
81 | File appFile = macPackager.getAppFile();
82 |
83 | tarTask.from(appFolder, copySpec -> {
84 | copySpec.include(appFile.getName() + "/**");
85 | copySpec.exclude(appFile.getName() + "/Contents/MacOS/" + executable.getName());
86 | copySpec.exclude(appFile.getName() + "/Contents/MacOS/universalJavaApplicationStub");
87 | copySpec.exclude(appFile.getName() + "/Contents/PlugIns/" + jreDirectoryName + "/Contents/Home/bin/*");
88 | copySpec.exclude(appFile.getName() + "/Contents/Resources/scripts/*");
89 |
90 | });
91 | tarTask.from(appFolder, copySpec -> {
92 | copySpec.include(appFile.getName() + "/Contents/MacOS/" + executable.getName());
93 | copySpec.include(appFile.getName() + "/Contents/MacOS/universalJavaApplicationStub");
94 | copySpec.include(appFile.getName() + "/Contents/PlugIns/" + jreDirectoryName + "/Contents/Home/bin/*");
95 | copySpec.include(appFile.getName() + "/Contents/Resources/scripts/*");
96 | copySpec.setFileMode(0755);
97 | });
98 |
99 | }
100 |
101 | tarTask.getActions().forEach(action -> action.execute(tarTask));
102 |
103 | return tarFile;
104 | }
105 |
106 | private Tar createTarTask() {
107 | return Context.getGradleContext().getProject().getTasks().create("createTarball_" + UUID.randomUUID(), Tar.class);
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/gradle/CreateWindowsExeLaunch4j.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.gradle;
2 |
3 | import java.io.File;
4 | import java.util.HashSet;
5 | import java.util.List;
6 |
7 | import net.jsign.WindowsSigner;
8 | import org.apache.commons.lang3.StringUtils;
9 |
10 | import edu.sc.seis.launch4j.tasks.Launch4jLibraryTask;
11 | import io.github.fvarrui.javapackager.model.WindowsConfig;
12 | import io.github.fvarrui.javapackager.model.WindowsExeCreationTool;
13 | import io.github.fvarrui.javapackager.packagers.AbstractCreateWindowsExe;
14 | import io.github.fvarrui.javapackager.packagers.Context;
15 | import io.github.fvarrui.javapackager.packagers.WindowsPackager;
16 | import io.github.fvarrui.javapackager.utils.FileUtils;
17 |
18 | /**
19 | * Creates Windows native executable on Gradle context
20 | */
21 | public class CreateWindowsExeLaunch4j extends AbstractCreateWindowsExe {
22 |
23 | public CreateWindowsExeLaunch4j() {
24 | super(WindowsExeCreationTool.launch4j);
25 | }
26 |
27 | @Override
28 | protected File doApply(WindowsPackager packager) throws Exception {
29 |
30 | List vmArgs = packager.getVmArgs();
31 | WindowsConfig winConfig = packager.getWinConfig();
32 | File executable = packager.getExecutable();
33 | String mainClass = packager.getMainClass();
34 | boolean useResourcesAsWorkingDir = packager.isUseResourcesAsWorkingDir();
35 | boolean bundleJre = packager.getBundleJre();
36 | String jreDirectoryName = packager.getJreDirectoryName();
37 | String jreMinVersion = packager.getJreMinVersion();
38 | File jarFile = packager.getJarFile();
39 | File appFolder = packager.getAppFolder();
40 |
41 | createAssets(packager); // creates a folder only for launch4j assets
42 |
43 | // copies JAR to app folder
44 | String jarPath;
45 | if (winConfig.isWrapJar()) {
46 | jarPath = getGenericJar().getAbsolutePath();
47 | } else {
48 | FileUtils.copyFileToFolder(jarFile, appFolder);
49 | jarPath = jarFile.getName();
50 | }
51 |
52 | Launch4jLibraryTask l4jTask = Context.getGradleContext().getLibraryTask();
53 | l4jTask.getDuplicatesStrategy().set(Context.getGradleContext().getDuplicatesStrategy());
54 | l4jTask.getOutputs().upToDateWhen(task -> false);
55 | l4jTask.getHeaderType().set(winConfig.getHeaderType().toString());
56 | l4jTask.getJarFiles().set(Context.getGradleContext().getProject().files(jarPath));
57 | l4jTask.getDontWrapJar().set(!winConfig.isWrapJar());
58 | l4jTask.getOutfile().set(getGenericExe().getName());
59 | l4jTask.getIcon().set(getGenericIcon().getAbsolutePath());
60 | l4jTask.getManifest().set(getGenericManifest().getAbsolutePath());
61 | l4jTask.getMainClassName().set(mainClass);
62 | l4jTask.getClasspath().set(new HashSet<>(packager.getClasspaths()));
63 | l4jTask.getChdir().set(useResourcesAsWorkingDir ? "." : "");
64 | if (bundleJre) {
65 | l4jTask.getBundledJrePath().set(jreDirectoryName);
66 | }
67 | if (!StringUtils.isBlank(jreMinVersion)) {
68 | l4jTask.getJreMinVersion().set(jreMinVersion);
69 | }
70 | l4jTask.getJvmOptions().addAll(vmArgs);
71 | l4jTask.getVersion().set(winConfig.getProductVersion());
72 | l4jTask.getTextVersion().set(winConfig.getTxtProductVersion());
73 | l4jTask.getCopyright().set(winConfig.getCopyright());
74 | l4jTask.getCompanyName().set(winConfig.getCompanyName());
75 | l4jTask.getFileDescription().set(winConfig.getFileDescription());
76 | l4jTask.getProductName().set(winConfig.getProductName());
77 | l4jTask.getInternalName().set(winConfig.getInternalName());
78 | l4jTask.getTrademarks().set(winConfig.getTrademarks());
79 | l4jTask.getLanguage().set(winConfig.getLanguage());
80 | l4jTask.getActions().forEach(action -> action.execute(l4jTask));
81 |
82 | FileUtils.copyFileToFile(getGenericExe(), executable);
83 |
84 | return createBootstrapScript(packager);
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/gradle/CreateZipball.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.gradle;
2 |
3 | import java.io.File;
4 | import java.util.UUID;
5 |
6 | import org.gradle.api.tasks.bundling.Zip;
7 |
8 | import io.github.fvarrui.javapackager.model.Platform;
9 | import io.github.fvarrui.javapackager.packagers.ArtifactGenerator;
10 | import io.github.fvarrui.javapackager.packagers.Context;
11 | import io.github.fvarrui.javapackager.packagers.MacPackager;
12 | import io.github.fvarrui.javapackager.packagers.Packager;
13 |
14 | /**
15 | * Creates zipball (zip file) on Gradle context
16 | */
17 | public class CreateZipball extends ArtifactGenerator {
18 |
19 | public CreateZipball() {
20 | super("Zipball");
21 | }
22 |
23 | @Override
24 | public boolean skip(Packager packager) {
25 | return !packager.getCreateZipball();
26 | }
27 |
28 | @Override
29 | protected File doApply(Packager packager) throws Exception {
30 |
31 | String name = packager.getName();
32 | String version = packager.getVersion();
33 | Platform platform = packager.getPlatform();
34 | File outputDirectory = packager.getOutputDirectory();
35 | File appFolder = packager.getAppFolder();
36 | File executable = packager.getExecutable();
37 | String jreDirectoryName = packager.getJreDirectoryName();
38 |
39 | String zipFileName = packager.getZipballName() != null ? packager.getZipballName() : name + "-" + version + "-" + platform + ".zip";
40 | File zipFile = new File(outputDirectory, zipFileName);
41 |
42 | Zip zipTask = createZipTask();
43 | zipTask.setProperty("archiveFileName", zipFile.getName());
44 | zipTask.setProperty("destinationDirectory", outputDirectory);
45 |
46 | // if zipball is for windows platform
47 | if (Platform.windows.equals(platform)) {
48 |
49 | zipTask.from(appFolder.getParentFile(), copySpec -> {
50 | copySpec.include(appFolder.getName() + "/**");
51 | });
52 |
53 | }
54 |
55 | // if zipball is for linux platform
56 | else if (Platform.linux.equals(platform)) {
57 |
58 | zipTask.from(appFolder.getParentFile(), copySpec -> {
59 | copySpec.include(appFolder.getName() + "/**");
60 | copySpec.exclude(appFolder.getName() + "/" + executable.getName());
61 | copySpec.exclude(appFolder.getName() + "/" + jreDirectoryName + "/bin/*");
62 | copySpec.exclude(appFolder.getName() + "/scripts/*");
63 | });
64 | zipTask.from(appFolder.getParentFile(), copySpec -> {
65 | copySpec.include(appFolder.getName() + "/" + executable.getName());
66 | copySpec.include(appFolder.getName() + "/" + jreDirectoryName + "/bin/*");
67 | copySpec.include(appFolder.getName() + "/scripts/*");
68 | copySpec.setFileMode(0755);
69 | });
70 |
71 | }
72 |
73 | // if zipball is for macos platform
74 | else if (Platform.mac.equals(platform)) {
75 |
76 | MacPackager macPackager = (MacPackager) packager;
77 | File appFile = macPackager.getAppFile();
78 |
79 | zipTask.from(appFolder, copySpec -> {
80 | copySpec.include(appFile.getName() + "/**");
81 | copySpec.exclude(appFile.getName() + "/Contents/MacOS/" + executable.getName());
82 | copySpec.exclude(appFile.getName() + "/Contents/MacOS/universalJavaApplicationStub");
83 | copySpec.exclude(appFile.getName() + "/Contents/PlugIns/" + jreDirectoryName + "/Contents/Home/bin/*");
84 | copySpec.exclude(appFile.getName() + "/Contents/Resources/scripts/*");
85 | });
86 | zipTask.from(appFolder, copySpec -> {
87 | copySpec.include(appFile.getName() + "/Contents/MacOS/" + executable.getName());
88 | copySpec.include(appFile.getName() + "/Contents/MacOS/universalJavaApplicationStub");
89 | copySpec.include(appFile.getName() + "/Contents/PlugIns/" + jreDirectoryName + "/Contents/Home/bin/*");
90 | copySpec.include(appFile.getName() + "/Contents/Resources/scripts/*");
91 | copySpec.setFileMode(0755);
92 | });
93 |
94 | }
95 |
96 | zipTask.getActions().forEach(action -> action.execute(zipTask));
97 |
98 | return zipFile;
99 | }
100 |
101 | private Zip createZipTask() {
102 | return Context.getGradleContext().getProject().getTasks().create("createZipball_" + UUID.randomUUID(), Zip.class);
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/gradle/GradleContext.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.gradle;
2 |
3 | import java.io.File;
4 |
5 | import io.github.fvarrui.javapackager.packagers.*;
6 | import org.gradle.api.Project;
7 | import org.gradle.api.file.DuplicatesStrategy;
8 | import org.gradle.api.internal.provider.Providers;
9 | import org.gradle.api.logging.Logger;
10 | import org.gradle.api.plugins.JavaPluginExtension;
11 | import org.gradle.api.provider.Provider;
12 | import org.gradle.jvm.toolchain.JavaLauncher;
13 | import org.gradle.jvm.toolchain.JavaToolchainService;
14 | import org.gradle.jvm.toolchain.JavaToolchainSpec;
15 |
16 | import edu.sc.seis.launch4j.tasks.Launch4jLibraryTask;
17 |
18 | /**
19 | * Gradle context
20 | */
21 | public class GradleContext extends Context {
22 |
23 | private Project project;
24 | private Launch4jLibraryTask libraryTask;
25 | private DuplicatesStrategy duplicatesStrategy;
26 |
27 | public GradleContext(Project project) {
28 | super();
29 | this.project = project;
30 | }
31 |
32 | public Logger getLogger() {
33 | return project.getLogger();
34 | }
35 |
36 | public Project getProject() {
37 | return project;
38 | }
39 |
40 | @Override
41 | public File getRootDir() {
42 | return project.getRootDir();
43 | }
44 |
45 | @Override
46 | public File getBuildDir() {
47 | return project.getBuildDir();
48 | }
49 |
50 | @Override
51 | public File createRunnableJar(Packager packager) throws Exception {
52 | return new CreateRunnableJar().apply(packager);
53 | }
54 |
55 | @Override
56 | public File copyDependencies(Packager packager) throws Exception {
57 | return new CopyDependencies().apply(packager);
58 | }
59 |
60 | @Override
61 | public File createTarball(Packager packager) throws Exception {
62 | return new CreateTarball().apply(packager);
63 | }
64 |
65 | @Override
66 | public File createZipball(Packager packager) throws Exception {
67 | return new CreateZipball().apply(packager);
68 | }
69 |
70 | @Override
71 | public File resolveLicense(Packager packager) throws Exception {
72 | // do nothing
73 | return null;
74 | }
75 |
76 | public Launch4jLibraryTask getLibraryTask() {
77 | return libraryTask;
78 | }
79 |
80 | public void setLibraryTask(Launch4jLibraryTask libraryTask) {
81 | this.libraryTask = libraryTask;
82 | }
83 |
84 | public DuplicatesStrategy getDuplicatesStrategy() {
85 | return duplicatesStrategy;
86 | }
87 |
88 | public void setDuplicatesStrategy(DuplicatesStrategy duplicatesStrategy) {
89 | this.duplicatesStrategy = duplicatesStrategy;
90 | }
91 |
92 | /**
93 | * Returns project's default toolchain
94 | *
95 | * @return Default toolchain
96 | */
97 | public File getDefaultToolchain() {
98 | if (project.getGradle().getGradleVersion().compareTo("7") >= 0)
99 | return getToolchain();
100 | else
101 | return super.getDefaultToolchain();
102 | }
103 |
104 | private File getToolchain() {
105 |
106 | // Default toolchain
107 | JavaToolchainSpec toolchain = project.getExtensions().getByType(JavaPluginExtension.class).getToolchain();
108 |
109 | // acquire a provider that returns the launcher for the toolchain
110 | JavaToolchainService service = project.getExtensions().getByType(JavaToolchainService.class);
111 | Provider defaultLauncher = service.launcherFor(toolchain).orElse(Providers.notDefined());
112 |
113 | if (defaultLauncher.isPresent()) {
114 | return defaultLauncher.get().getMetadata().getInstallationPath().getAsFile();
115 | }
116 | return super.getDefaultToolchain();
117 |
118 | }
119 |
120 | @Override
121 | public File createWindowsExe(WindowsPackager packager) throws Exception {
122 | AbstractCreateWindowsExe createWindowsExe;
123 | switch (packager.getWinConfig().getExeCreationTool()) {
124 | case launch4j: createWindowsExe = new CreateWindowsExeLaunch4j(); break;
125 | case winrun4j: createWindowsExe = new CreateWindowsExeWinRun4j(); break;
126 | case why: createWindowsExe = new CreateWindowsExeWhy(); break;
127 | default: return null;
128 | }
129 | if (!createWindowsExe.skip(packager)) {
130 | return createWindowsExe.apply(packager);
131 | }
132 | return null;
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePlugin.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.gradle;
2 |
3 | import java.util.UUID;
4 |
5 | import org.gradle.api.Plugin;
6 | import org.gradle.api.Project;
7 |
8 | import edu.sc.seis.launch4j.tasks.Launch4jLibraryTask;
9 | import io.github.fvarrui.javapackager.packagers.Context;
10 |
11 | /**
12 | * JavaPackager Gradle plugin
13 | */
14 | public class PackagePlugin implements Plugin {
15 |
16 | public static final String GROUP_NAME = "JavaPackager";
17 | public static final String SETTINGS_EXT_NAME = "javapackager";
18 | public static final String PACKAGE_TASK_NAME = "package";
19 |
20 | @Override
21 | public void apply(Project project) {
22 | Context.setContext(new GradleContext(project));
23 |
24 | project.getPluginManager().apply("java");
25 | project.getPluginManager().apply("edu.sc.seis.launch4j");
26 |
27 | project.getExtensions().create(SETTINGS_EXT_NAME, PackagePluginExtension.class, project);
28 | project.getTasks().create(PACKAGE_TASK_NAME, PackageTask.class).dependsOn("build");
29 |
30 | Context.getGradleContext().setLibraryTask(project.getTasks().create("launch4j_" + UUID.randomUUID(), Launch4jLibraryTask.class));
31 |
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePluginExtension.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.gradle;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 |
7 | import org.gradle.api.Project;
8 | import org.gradle.api.file.DuplicatesStrategy;
9 |
10 | import groovy.lang.Closure;
11 | import io.github.fvarrui.javapackager.model.Arch;
12 | import io.github.fvarrui.javapackager.model.LinuxConfig;
13 | import io.github.fvarrui.javapackager.model.MacConfig;
14 | import io.github.fvarrui.javapackager.model.Manifest;
15 | import io.github.fvarrui.javapackager.model.Platform;
16 | import io.github.fvarrui.javapackager.model.Scripts;
17 | import io.github.fvarrui.javapackager.model.WindowsConfig;
18 | import io.github.fvarrui.javapackager.packagers.PackagerSettings;
19 |
20 | /**
21 | * JavaPackager plugin extension for Gradle
22 | */
23 | public class PackagePluginExtension extends PackagerSettings {
24 |
25 | private Project project;
26 | private DuplicatesStrategy duplicatesStrategy;
27 |
28 | public PackagePluginExtension(Project project) {
29 | super();
30 | this.project = project;
31 | this.platform = Platform.auto;
32 | this.additionalModules = new ArrayList<>();
33 | this.additionalModulePaths = new ArrayList<>();
34 | this.additionalResources = new ArrayList<>();
35 | this.administratorRequired = false;
36 | this.assetsDir = new File(project.getProjectDir(), "assets");
37 | this.bundleJre = true;
38 | this.copyDependencies = true;
39 | this.createTarball = false;
40 | this.createZipball = false;
41 | this.customizedJre = true;
42 | this.description = project.getDescription();
43 | this.extra = new HashMap<>();
44 | this.generateInstaller = true;
45 | this.jreDirectoryName = "jre";
46 | this.linuxConfig = new LinuxConfig();
47 | this.macConfig = new MacConfig();
48 | this.manifest = new Manifest();
49 | this.modules = new ArrayList<>();
50 | this.name = project.getName();
51 | this.organizationEmail = "";
52 | this.useResourcesAsWorkingDir = true;
53 | this.vmArgs = new ArrayList<>();
54 | this.winConfig = new WindowsConfig();
55 | this.outputDirectory = project.getBuildDir();
56 | this.scripts = new Scripts();
57 | this.forceInstaller = false;
58 | this.arch = Arch.getDefault();
59 | this.duplicatesStrategy = DuplicatesStrategy.WARN;
60 | }
61 |
62 | public LinuxConfig linuxConfig(Closure closure) {
63 | linuxConfig = new LinuxConfig();
64 | project.configure(linuxConfig, closure);
65 | return linuxConfig;
66 | }
67 |
68 | public MacConfig macConfig(Closure closure) {
69 | macConfig = new MacConfig();
70 | project.configure(macConfig, closure);
71 | return macConfig;
72 | }
73 |
74 | public WindowsConfig winConfig(Closure closure) {
75 | winConfig = new WindowsConfig();
76 | project.configure(winConfig, closure);
77 | return winConfig;
78 | }
79 |
80 | public Manifest manifest(Closure closure) {
81 | manifest = new Manifest();
82 | project.configure(manifest, closure);
83 | return manifest;
84 | }
85 |
86 | public Scripts scripts(Closure closure) {
87 | scripts = new Scripts();
88 | project.configure(scripts, closure);
89 | return scripts;
90 | }
91 |
92 | public void setDuplicatesStrategy(DuplicatesStrategy duplicatesStrategy) {
93 | this.duplicatesStrategy = duplicatesStrategy;
94 | }
95 |
96 | public DuplicatesStrategy getDuplicatesStrategy() {
97 | return duplicatesStrategy;
98 | }
99 |
100 | }
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/maven/CopyDependencies.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.maven;
2 |
3 | import static org.twdata.maven.mojoexecutor.MojoExecutor.artifactId;
4 | import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration;
5 | import static org.twdata.maven.mojoexecutor.MojoExecutor.element;
6 | import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo;
7 | import static org.twdata.maven.mojoexecutor.MojoExecutor.goal;
8 | import static org.twdata.maven.mojoexecutor.MojoExecutor.groupId;
9 | import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin;
10 | import static org.twdata.maven.mojoexecutor.MojoExecutor.version;
11 |
12 | import java.io.File;
13 |
14 | import org.apache.maven.plugin.MojoExecutionException;
15 |
16 | import io.github.fvarrui.javapackager.packagers.ArtifactGenerator;
17 | import io.github.fvarrui.javapackager.packagers.Context;
18 | import io.github.fvarrui.javapackager.packagers.Packager;
19 |
20 | /**
21 | * Copies all dependencies to app folder on Maven context
22 | */
23 | public class CopyDependencies extends ArtifactGenerator {
24 |
25 | public CopyDependencies() {
26 | super("Dependencies");
27 | }
28 |
29 | @Override
30 | public boolean skip(Packager packager) {
31 | return !packager.getCopyDependencies();
32 | }
33 |
34 | @Override
35 | protected File doApply(Packager packager) {
36 |
37 | File libsFolder = new File(packager.getJarFileDestinationFolder(), "libs");
38 |
39 | // invokes 'maven-dependency-plugin' plugin to copy dependecies to app libs folder
40 | try {
41 |
42 | executeMojo(
43 | plugin(
44 | groupId("org.apache.maven.plugins"),
45 | artifactId("maven-dependency-plugin"),
46 | version("3.1.1")
47 | ),
48 | goal("copy-dependencies"),
49 | configuration(
50 | element("outputDirectory", libsFolder.getAbsolutePath())
51 | ),
52 | Context.getMavenContext().getEnv()
53 | );
54 |
55 | } catch (MojoExecutionException e) {
56 |
57 | throw new RuntimeException("Error copying dependencies: " + e.getMessage());
58 |
59 | }
60 |
61 | return libsFolder;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/maven/CreateRunnableJar.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.maven;
2 |
3 | import static org.twdata.maven.mojoexecutor.MojoExecutor.artifactId;
4 | import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration;
5 | import static org.twdata.maven.mojoexecutor.MojoExecutor.element;
6 | import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo;
7 | import static org.twdata.maven.mojoexecutor.MojoExecutor.goal;
8 | import static org.twdata.maven.mojoexecutor.MojoExecutor.groupId;
9 | import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin;
10 | import static org.twdata.maven.mojoexecutor.MojoExecutor.version;
11 |
12 | import java.io.File;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.stream.Collectors;
16 |
17 | import org.apache.maven.plugin.MojoExecutionException;
18 | import org.twdata.maven.mojoexecutor.MojoExecutor.Element;
19 | import org.twdata.maven.mojoexecutor.MojoExecutor.ExecutionEnvironment;
20 |
21 | import io.github.fvarrui.javapackager.model.Manifest;
22 | import io.github.fvarrui.javapackager.packagers.ArtifactGenerator;
23 | import io.github.fvarrui.javapackager.packagers.Context;
24 | import io.github.fvarrui.javapackager.packagers.Packager;
25 | import io.github.fvarrui.javapackager.utils.Logger;
26 | import io.github.fvarrui.javapackager.utils.MojoExecutorUtils;
27 |
28 | /**
29 | * Creates a runnable jar file from sources on Maven context
30 | */
31 | public class CreateRunnableJar extends ArtifactGenerator {
32 |
33 | public CreateRunnableJar() {
34 | super("Runnable JAR");
35 | }
36 |
37 | @Override
38 | protected File doApply(Packager packager) {
39 |
40 | String classifier = "runnable";
41 | String mainClass = packager.getMainClass();
42 | File outputDirectory = packager.getOutputDirectory();
43 | ExecutionEnvironment env = Context.getMavenContext().getEnv();
44 | Manifest manifest = packager.getManifest();
45 |
46 | List archive = new ArrayList<>();
47 | archive.add(
48 | element("manifest",
49 | element("addClasspath", "true"),
50 | element("classpathPrefix", "libs/"),
51 | element("mainClass", mainClass),
52 | element("useUniqueVersions", "false")
53 | )
54 | );
55 | if (manifest != null) {
56 |
57 | archive.add(MojoExecutorUtils.mapToElement("manifestEntries", manifest.getAdditionalEntries()));
58 |
59 | List manifestSections =
60 | manifest
61 | .getSections()
62 | .stream()
63 | .map(s -> element("manifestSection",
64 | element("Name", s.getName()),
65 | MojoExecutorUtils.mapToElement("manifestEntries", s.getEntries())
66 | ))
67 | .collect(Collectors.toList());
68 |
69 | archive.add(element("manifestSections", manifestSections.toArray(new Element[manifestSections.size()])));
70 |
71 | }
72 |
73 | try {
74 |
75 | executeMojo(
76 | plugin(
77 | groupId("org.apache.maven.plugins"),
78 | artifactId("maven-jar-plugin"),
79 | version("3.3.0")
80 | ),
81 | goal("jar"),
82 | configuration(
83 | element("classifier", classifier),
84 | element("archive", archive.toArray(new Element[archive.size()])),
85 | element("outputDirectory", outputDirectory.getAbsolutePath())
86 | ),
87 | env
88 | );
89 |
90 | } catch (MojoExecutionException e) {
91 |
92 | Logger.error("Runnable jar creation failed! " + e.getMessage());
93 | throw new RuntimeException(e);
94 |
95 | }
96 |
97 | // gets build.finalName value
98 | String finalName = Context.getMavenContext().getEnv().getMavenProject().getBuild().getFinalName();
99 |
100 | // creates file pointing to generated jar file
101 | return new File(outputDirectory, finalName + "-" + classifier + ".jar");
102 |
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/maven/CreateTarball.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.maven;
2 |
3 | import static org.twdata.maven.mojoexecutor.MojoExecutor.artifactId;
4 | import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration;
5 | import static org.twdata.maven.mojoexecutor.MojoExecutor.element;
6 | import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo;
7 | import static org.twdata.maven.mojoexecutor.MojoExecutor.goal;
8 | import static org.twdata.maven.mojoexecutor.MojoExecutor.groupId;
9 | import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin;
10 | import static org.twdata.maven.mojoexecutor.MojoExecutor.version;
11 |
12 | import java.io.File;
13 |
14 | import io.github.fvarrui.javapackager.model.Platform;
15 | import io.github.fvarrui.javapackager.packagers.ArtifactGenerator;
16 | import io.github.fvarrui.javapackager.packagers.Context;
17 | import io.github.fvarrui.javapackager.packagers.Packager;
18 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
19 |
20 | /**
21 | * Creates tarball (tar.gz file) on Maven context
22 | */
23 | public class CreateTarball extends ArtifactGenerator {
24 |
25 | public CreateTarball() {
26 | super("Tarball");
27 | }
28 |
29 | @Override
30 | public boolean skip(Packager packager) {
31 | return !packager.getCreateTarball();
32 | }
33 |
34 | @Override
35 | protected File doApply(Packager packager) {
36 |
37 | File assetsFolder = packager.getAssetsFolder();
38 | Platform platform = packager.getPlatform();
39 | File outputDirectory = packager.getOutputDirectory();
40 |
41 | try {
42 |
43 | // generate assembly.xml file
44 | File assemblyFile = new File(assetsFolder, "assembly-tarball-" + platform + ".xml");
45 | VelocityUtils.render(platform + "/assembly.xml.vtl", assemblyFile, packager);
46 |
47 | // output file format
48 | String format = "tar.gz";
49 |
50 | // invokes plugin to assemble tarball
51 | executeMojo(
52 | plugin(
53 | groupId("org.apache.maven.plugins"),
54 | artifactId("maven-assembly-plugin"),
55 | version("3.1.1")
56 | ),
57 | goal("single"),
58 | configuration(
59 | element("outputDirectory", outputDirectory.getAbsolutePath()),
60 | element("formats", element("format", format)),
61 | element("descriptors", element("descriptor", assemblyFile.getAbsolutePath())),
62 | element("appendAssemblyId", "false")
63 | ),
64 | Context.getMavenContext().getEnv()
65 | );
66 |
67 | // get generated filename
68 | String finalName = Context.getMavenContext().getEnv().getMavenProject().getBuild().getFinalName();
69 | File finalFile = new File(outputDirectory, finalName + "." + format);
70 |
71 | // get desired file name
72 | String tarName = packager.getTarballName() != null ? packager.getTarballName() : finalName + "-" + platform;
73 | File tarFile = new File(outputDirectory, tarName + "." + format);
74 |
75 | // rename generated to desired
76 | finalFile.renameTo(tarFile);
77 |
78 | return tarFile;
79 |
80 | } catch (Exception e) {
81 |
82 | throw new RuntimeException(e);
83 |
84 | }
85 |
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/maven/CreateWindowsExeLaunch4j.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.maven;
2 |
3 | import static org.twdata.maven.mojoexecutor.MojoExecutor.artifactId;
4 | import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration;
5 | import static org.twdata.maven.mojoexecutor.MojoExecutor.element;
6 | import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo;
7 | import static org.twdata.maven.mojoexecutor.MojoExecutor.goal;
8 | import static org.twdata.maven.mojoexecutor.MojoExecutor.groupId;
9 | import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin;
10 | import static org.twdata.maven.mojoexecutor.MojoExecutor.version;
11 |
12 | import java.io.File;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.stream.Collectors;
16 |
17 | import net.jsign.WindowsSigner;
18 | import org.apache.commons.lang3.StringUtils;
19 | import org.twdata.maven.mojoexecutor.MojoExecutor.Element;
20 |
21 | import io.github.fvarrui.javapackager.model.Arch;
22 | import io.github.fvarrui.javapackager.model.WindowsConfig;
23 | import io.github.fvarrui.javapackager.model.WindowsExeCreationTool;
24 | import io.github.fvarrui.javapackager.packagers.AbstractCreateWindowsExe;
25 | import io.github.fvarrui.javapackager.packagers.Context;
26 | import io.github.fvarrui.javapackager.packagers.WindowsPackager;
27 | import io.github.fvarrui.javapackager.utils.FileUtils;
28 | import io.github.fvarrui.javapackager.utils.Logger;
29 |
30 | /**
31 | * Creates Windows executable with Maven
32 | */
33 | public class CreateWindowsExeLaunch4j extends AbstractCreateWindowsExe {
34 |
35 | public CreateWindowsExeLaunch4j() {
36 | super(WindowsExeCreationTool.launch4j);
37 | }
38 |
39 | @Override
40 | protected File doApply(WindowsPackager packager) throws Exception {
41 |
42 | List vmArgs = packager.getVmArgs();
43 | WindowsConfig winConfig = packager.getWinConfig();
44 | File executable = packager.getExecutable();
45 | String mainClass = packager.getMainClass();
46 | boolean useResourcesAsWorkingDir = packager.isUseResourcesAsWorkingDir();
47 | boolean bundleJre = packager.getBundleJre();
48 | String jreDirectoryName = packager.getJreDirectoryName();
49 | String classpath = packager.getClasspath();
50 | String jreMinVersion = packager.getJreMinVersion();
51 | File jarFile = packager.getJarFile();
52 | File appFolder = packager.getAppFolder();
53 | Arch arch = packager.getArch();
54 |
55 | createAssets(packager);
56 |
57 | // warns about architecture
58 | if (arch != Arch.x86) {
59 | Logger.warn("Launch4J only can generate 32-bit executable");
60 | }
61 |
62 | // copies JAR to app folder
63 | String jarPath;
64 | if (winConfig.isWrapJar()) {
65 | jarPath = getGenericJar().getAbsolutePath();
66 | } else {
67 | FileUtils.copyFileToFolder(jarFile, appFolder);
68 | jarPath = jarFile.getName();
69 | }
70 |
71 | List jreElements = new ArrayList<>();
72 | jreElements.add(element("opts", vmArgs.stream().map(arg -> element("opt", arg)).toArray(Element[]::new)));
73 | jreElements.add(element("path", bundleJre ? jreDirectoryName : "%JAVA_HOME%;%PATH%"));
74 | if (!StringUtils.isBlank(jreMinVersion)) {
75 | jreElements.add(element("minVersion", jreMinVersion));
76 | }
77 |
78 | List pluginConfig = new ArrayList<>();
79 | pluginConfig.add(element("headerType", "" + winConfig.getHeaderType()));
80 | pluginConfig.add(element("jar", jarPath));
81 | pluginConfig.add(element("dontWrapJar", "" + !winConfig.isWrapJar()));
82 | pluginConfig.add(element("outfile", getGenericExe().getAbsolutePath()));
83 | pluginConfig.add(element("icon", getGenericIcon().getAbsolutePath()));
84 | pluginConfig.add(element("manifest", getGenericManifest().getAbsolutePath()));
85 | pluginConfig.add(
86 | element("classPath",
87 | element("mainClass", mainClass),
88 | element("preCp", classpath),
89 | element("addDependencies", "false")
90 | )
91 | );
92 | pluginConfig.add(element("chdir", useResourcesAsWorkingDir ? "." : ""));
93 | pluginConfig.add(element("jre", jreElements.toArray(new Element[0])));
94 | pluginConfig.add(
95 | element("versionInfo",
96 | element("fileVersion", winConfig.getFileVersion()),
97 | element("txtFileVersion", winConfig.getTxtFileVersion()),
98 | element("productVersion", winConfig.getProductVersion()),
99 | element("txtProductVersion", winConfig.getTxtProductVersion()),
100 | element("copyright", winConfig.getCopyright()),
101 | element("companyName", winConfig.getCompanyName()),
102 | element("fileDescription", winConfig.getFileDescription()),
103 | element("productName", winConfig.getProductName()),
104 | element("internalName", winConfig.getInternalName()),
105 | element("originalFilename", winConfig.getOriginalFilename()),
106 | element("trademarks", winConfig.getTrademarks()),
107 | element("language", winConfig.getLanguage())
108 | )
109 | );
110 |
111 | // invokes launch4j plugin to generate windows executable
112 | try {
113 |
114 | executeMojo(
115 | plugin(
116 | groupId("com.akathist.maven.plugins.launch4j"),
117 | artifactId("launch4j-maven-plugin"),
118 | version("2.4.1")
119 | ),
120 | goal("launch4j"),
121 | configuration(pluginConfig.toArray(new Element[0])),
122 | Context.getMavenContext().getEnv()
123 | );
124 |
125 | FileUtils.copyFileToFile(getGenericExe(), executable);
126 |
127 | } catch (Exception ex) {
128 | throw new RuntimeException(ex);
129 | }
130 |
131 | return createBootstrapScript(packager);
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/maven/CreateZipball.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.maven;
2 |
3 | import static org.twdata.maven.mojoexecutor.MojoExecutor.artifactId;
4 | import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration;
5 | import static org.twdata.maven.mojoexecutor.MojoExecutor.element;
6 | import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo;
7 | import static org.twdata.maven.mojoexecutor.MojoExecutor.goal;
8 | import static org.twdata.maven.mojoexecutor.MojoExecutor.groupId;
9 | import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin;
10 | import static org.twdata.maven.mojoexecutor.MojoExecutor.version;
11 |
12 | import java.io.File;
13 |
14 | import io.github.fvarrui.javapackager.model.Platform;
15 | import io.github.fvarrui.javapackager.packagers.ArtifactGenerator;
16 | import io.github.fvarrui.javapackager.packagers.Context;
17 | import io.github.fvarrui.javapackager.packagers.Packager;
18 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
19 |
20 | /**
21 | * Creates zipball (zip file) on Maven context
22 | */
23 | public class CreateZipball extends ArtifactGenerator {
24 |
25 | public CreateZipball() {
26 | super("Zipball");
27 | }
28 |
29 | @Override
30 | public boolean skip(Packager packager) {
31 | return !packager.getCreateZipball();
32 | }
33 |
34 | @Override
35 | protected File doApply(Packager packager) {
36 |
37 | File assetsFolder = packager.getAssetsFolder();
38 | Platform platform = packager.getPlatform();
39 | File outputDirectory = packager.getOutputDirectory();
40 |
41 | try {
42 |
43 | // generate assembly.xml file
44 | File assemblyFile = new File(assetsFolder, "assembly-zipball-" + platform + ".xml");
45 | VelocityUtils.render(platform + "/assembly.xml.vtl", assemblyFile, packager);
46 |
47 | // zip file name and format
48 | String format = "zip";
49 |
50 | // invokes plugin to assemble zipball and/or tarball
51 | executeMojo(
52 | plugin(
53 | groupId("org.apache.maven.plugins"),
54 | artifactId("maven-assembly-plugin"),
55 | version("3.1.1")
56 | ),
57 | goal("single"),
58 | configuration(
59 | element("outputDirectory", outputDirectory.getAbsolutePath()),
60 | element("formats", element("format", format)),
61 | element("descriptors", element("descriptor", assemblyFile.getAbsolutePath())),
62 | element("appendAssemblyId", "false")
63 | ),
64 | Context.getMavenContext().getEnv()
65 | );
66 |
67 | // gets generated filename
68 | String finalName = Context.getMavenContext().getEnv().getMavenProject().getBuild().getFinalName();
69 | File finalFile = new File(outputDirectory, finalName + "." + format);
70 |
71 | // gets desired file name
72 | String zipName = packager.getZipballName() != null ? packager.getZipballName() : finalName + "-" + platform;
73 | File zipFile = new File(outputDirectory, zipName + "." + format);
74 |
75 | // rename generated to desired
76 | finalFile.renameTo(zipFile);
77 |
78 | return zipFile;
79 |
80 | } catch (Exception e) {
81 |
82 | throw new RuntimeException(e);
83 |
84 | }
85 |
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/maven/MavenContext.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.maven;
2 |
3 | import java.io.File;
4 | import java.time.Year;
5 |
6 | import org.apache.commons.lang3.StringUtils;
7 | import org.apache.maven.model.Organization;
8 | import org.apache.maven.plugin.logging.Log;
9 | import org.apache.maven.project.MavenProject;
10 | import org.twdata.maven.mojoexecutor.MojoExecutor.ExecutionEnvironment;
11 |
12 | import io.github.fvarrui.javapackager.packagers.AbstractCreateWindowsExe;
13 | import io.github.fvarrui.javapackager.packagers.Context;
14 | import io.github.fvarrui.javapackager.packagers.CreateWindowsExeWhy;
15 | import io.github.fvarrui.javapackager.packagers.CreateWindowsExeWinRun4j;
16 | import io.github.fvarrui.javapackager.packagers.Packager;
17 | import io.github.fvarrui.javapackager.packagers.WindowsPackager;
18 |
19 | /**
20 | * Maven context
21 | */
22 | public class MavenContext extends Context {
23 |
24 | private Log logger;
25 | private ExecutionEnvironment env;
26 |
27 | public MavenContext(ExecutionEnvironment env, Log logger) {
28 | super();
29 | this.env = env;
30 | this.logger = logger;
31 |
32 | // initialize some default params on project (avoid launch4j-maven-plugin warnings)
33 | MavenProject project = env.getMavenProject();
34 | if (project.getOrganization() == null) {
35 | project.setOrganization(new Organization());
36 | }
37 | // set default organization name
38 | if (StringUtils.isBlank(project.getOrganization().getName())) {
39 | project.getOrganization().setName(Packager.DEFAULT_ORGANIZATION_NAME);
40 | }
41 | // set default inception year
42 | if (StringUtils.isBlank(project.getInceptionYear())) {
43 | project.setInceptionYear(Year.now().toString());
44 | }
45 | // set default description
46 | if (StringUtils.isBlank(project.getDescription())) {
47 | project.setDescription(project.getArtifactId());
48 | }
49 | }
50 |
51 | public ExecutionEnvironment getEnv() {
52 | return env;
53 | }
54 |
55 | public Log getLogger() {
56 | return logger;
57 | }
58 |
59 | @Override
60 | public File getRootDir() {
61 | return env.getMavenProject().getBasedir();
62 | }
63 |
64 | @Override
65 | public File getBuildDir() {
66 | return new File(env.getMavenProject().getBuild().getDirectory());
67 | }
68 |
69 | @Override
70 | public File createRunnableJar(Packager packager) throws Exception {
71 | return new CreateRunnableJar().apply(packager);
72 | }
73 |
74 | @Override
75 | public File copyDependencies(Packager packager) throws Exception {
76 | return new CopyDependencies().apply(packager);
77 | }
78 |
79 | @Override
80 | public File createTarball(Packager packager) throws Exception {
81 | return new CreateTarball().apply(packager);
82 | }
83 |
84 | @Override
85 | public File createZipball(Packager packager) throws Exception {
86 | return new CreateZipball().apply(packager);
87 | }
88 |
89 | @Override
90 | public File resolveLicense(Packager packager) throws Exception {
91 | return new ResolveLicenseFromPOM().apply(packager);
92 | }
93 |
94 | @Override
95 | public File createWindowsExe(WindowsPackager packager) throws Exception {
96 | AbstractCreateWindowsExe createWindowsExe;
97 | switch (packager.getWinConfig().getExeCreationTool()) {
98 | case launch4j: createWindowsExe = new CreateWindowsExeLaunch4j(); break;
99 | case why: createWindowsExe = new CreateWindowsExeWhy(); break;
100 | case winrun4j: createWindowsExe = new CreateWindowsExeWinRun4j(); break;
101 | default: return null;
102 | }
103 | if (!createWindowsExe.skip(packager)) {
104 | return createWindowsExe.apply(packager);
105 | }
106 | return null;
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/maven/ResolveLicenseFromPOM.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.maven;
2 |
3 | import java.io.File;
4 | import java.net.MalformedURLException;
5 | import java.net.URI;
6 | import java.net.URISyntaxException;
7 | import java.net.URL;
8 | import java.util.List;
9 |
10 | import org.apache.maven.model.License;
11 |
12 | import io.github.fvarrui.javapackager.packagers.ArtifactGenerator;
13 | import io.github.fvarrui.javapackager.packagers.Context;
14 | import io.github.fvarrui.javapackager.packagers.Packager;
15 | import io.github.fvarrui.javapackager.utils.FileUtils;
16 | import io.github.fvarrui.javapackager.utils.Logger;
17 |
18 | /**
19 | * Creates a runnable jar file from sources on Maven context
20 | */
21 | public class ResolveLicenseFromPOM extends ArtifactGenerator {
22 |
23 | public ResolveLicenseFromPOM() {
24 | super("LICENSE");
25 | }
26 |
27 | @Override
28 | protected File doApply(Packager packager) {
29 | Logger.infoIndent("Trying to resolve license from POM ...");
30 |
31 | File licenseFile = packager.getLicenseFile();
32 | List licenses = Context.getMavenContext().getEnv().getMavenProject().getLicenses();
33 | File assetsFolder = packager.getAssetsFolder();
34 |
35 | // if license not specified, gets from pom
36 | if (licenseFile == null && !licenses.isEmpty()) {
37 | String urlStr = null;
38 | try {
39 | urlStr = licenses.get(0).getUrl();
40 | URL licenseUrl = new URI(urlStr).toURL();
41 | licenseFile = new File(assetsFolder, "LICENSE");
42 | FileUtils.downloadFromUrl(licenseUrl, licenseFile);
43 | } catch (URISyntaxException | MalformedURLException e) {
44 | Logger.error("Invalid license URL specified: " + urlStr);
45 | licenseFile = null;
46 | } catch (Exception e) {
47 | Logger.error("Cannot download license from " + urlStr);
48 | licenseFile = null;
49 | }
50 | }
51 |
52 | if (licenseFile != null)
53 | Logger.infoUnindent("License resolved " + licenseFile + "!");
54 | else
55 | Logger.infoUnindent("License not resolved!");
56 |
57 | return licenseFile;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/Arch.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import org.apache.commons.lang3.SystemUtils;
4 | import org.redline_rpm.header.Architecture;
5 |
6 | public enum Arch {
7 | aarch64,
8 | x64,
9 | x86;
10 |
11 | public static Arch getArch(String archString) {
12 | switch (archString) {
13 | case "x86":
14 | case "i386":
15 | case "i486":
16 | case "i586":
17 | case "i686":
18 | return x86;
19 | case "x86_64":
20 | case "amd64":
21 | return x64;
22 | case "aarch64":
23 | return aarch64;
24 | default:
25 | throw new IllegalArgumentException("Unknown architecture " + archString);
26 | }
27 | }
28 |
29 | public static Arch getDefault() {
30 | return getArch(SystemUtils.OS_ARCH);
31 | }
32 |
33 | public String toDebArchitecture() {
34 | switch (this) {
35 | case aarch64: return "arm64";
36 | case x64: return "amd64";
37 | case x86: return "i386";
38 | default: return null;
39 | }
40 | }
41 |
42 | public Architecture toRpmArchitecture() {
43 | switch (this) {
44 | case aarch64: return Architecture.AARCH64;
45 | case x64: return Architecture.X86_64;
46 | case x86: return Architecture.I386;
47 | default: return null;
48 | }
49 | }
50 |
51 | public String toMsiArchitecture() {
52 | switch (this) {
53 | case aarch64: return "arm64";
54 | case x64: return "x64";
55 | case x86: return "x86";
56 | default: return null;
57 | }
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/CFBundlePackageType.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.Serializable;
4 |
5 | public enum CFBundlePackageType implements Serializable {
6 | BNDL,
7 | APPL,
8 | FMWK
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/FileAssociation.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.Serializable;
4 |
5 | public class FileAssociation implements Serializable {
6 | private static final long serialVersionUID = -2777769245508048627L;
7 |
8 | private String mimeType;
9 | private String extension;
10 | private String description;
11 |
12 | public String getMimeType() {
13 | return mimeType;
14 | }
15 |
16 | public void setMimeType(String mimeType) {
17 | this.mimeType = mimeType;
18 | }
19 |
20 | public String getExtension() {
21 | return extension;
22 | }
23 |
24 | public void setExtension(String extension) {
25 | this.extension = extension;
26 | }
27 |
28 | public String getDescription() {
29 | return description;
30 | }
31 |
32 | public void setDescription(String description) {
33 | this.description = description;
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "FileAssociation [mimeType=" + mimeType + ", extension=" + extension + ", description=" + description
39 | + "]";
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/HeaderType.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | /**
4 | * Windows EXE header type
5 | */
6 | public enum HeaderType {
7 | gui,
8 | console;
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/InfoPlist.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.Serializable;
4 |
5 | public class InfoPlist implements Serializable {
6 | private static final long serialVersionUID = -1237535573669475709L;
7 |
8 | private String additionalEntries = "";
9 | private CFBundlePackageType bundlePackageType = CFBundlePackageType.BNDL;
10 |
11 | public String getAdditionalEntries() {
12 | return additionalEntries;
13 | }
14 |
15 | public void setAdditionalEntries(String additionalEntries) {
16 | this.additionalEntries = additionalEntries;
17 | }
18 |
19 | public CFBundlePackageType getBundlePackageType() {
20 | return bundlePackageType;
21 | }
22 |
23 | public void setBundlePackageType(CFBundlePackageType bundlePackageType) {
24 | this.bundlePackageType = bundlePackageType;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return "InfoPlist [additionalEntries=" + additionalEntries + ", bundlePackageType=" + bundlePackageType + "]";
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/LinuxConfig.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.File;
4 | import java.io.Serializable;
5 | import java.util.Arrays;
6 | import java.util.Collections;
7 | import java.util.List;
8 |
9 | import org.apache.commons.lang3.ObjectUtils;
10 |
11 | import io.github.fvarrui.javapackager.packagers.Packager;
12 |
13 | /**
14 | * JavaPackager GNU/Linux specific configuration
15 | */
16 | public class LinuxConfig implements Serializable {
17 | private static final long serialVersionUID = -1238166997019141904L;
18 |
19 | private List categories;
20 | private boolean generateDeb = true;
21 | private boolean generateRpm = true;
22 | private boolean generateAppImage = true;
23 | private File pngFile;
24 | private boolean wrapJar = true;
25 | private String installationPath;
26 |
27 | public void setCategories(List categories) {
28 | this.categories = categories;
29 | }
30 |
31 | public List getCategories() {
32 | return categories;
33 | }
34 |
35 | public boolean isGenerateDeb() {
36 | return generateDeb;
37 | }
38 |
39 | public void setGenerateDeb(boolean generateDeb) {
40 | this.generateDeb = generateDeb;
41 | }
42 |
43 | public boolean isGenerateRpm() {
44 | return generateRpm;
45 | }
46 |
47 | public void setGenerateRpm(boolean generateRpm) {
48 | this.generateRpm = generateRpm;
49 | }
50 |
51 | public boolean isGenerateAppImage() {
52 | return generateAppImage;
53 | }
54 |
55 | public void setGenerateAppImage(boolean generateAppImage) {
56 | this.generateAppImage = generateAppImage;
57 | }
58 |
59 | public File getPngFile() {
60 | return pngFile;
61 | }
62 |
63 | public void setPngFile(File pngFile) {
64 | this.pngFile = pngFile;
65 | }
66 |
67 | public boolean isWrapJar() {
68 | return wrapJar;
69 | }
70 |
71 | public void setWrapJar(boolean wrapJar) {
72 | this.wrapJar = wrapJar;
73 | }
74 |
75 | public String getInstallationPath() {
76 | return installationPath;
77 | }
78 |
79 | public void setInstallationPath(String installationPath) {
80 | this.installationPath = installationPath;
81 | }
82 |
83 | @Override
84 | public String toString() {
85 | return "LinuxConfig [categories=" + categories + ", generateDeb=" + generateDeb + ", generateRpm=" + generateRpm
86 | + ", generateAppImage=" + generateAppImage + ", pngFile=" + pngFile + ", wrapJar=" + wrapJar
87 | + ", installationPath=" + installationPath + "]";
88 | }
89 |
90 | /**
91 | * Tests GNU/Linux specific config and set defaults if not specified
92 | *
93 | * @param packager Packager
94 | */
95 | public void setDefaults(Packager packager) {
96 | this.setCategories((categories == null || categories.isEmpty()) ? Collections.singletonList("Utility") : categories);
97 | this.setInstallationPath(ObjectUtils.defaultIfNull(installationPath, "/opt"));
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/MacStartup.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | public enum MacStartup {
4 | UNIVERSAL,
5 | X86_64,
6 | ARM64,
7 | SCRIPT
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/Manifest.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | /**
10 | * JAR manifest configuration
11 | */
12 | public class Manifest implements Serializable {
13 | private static final long serialVersionUID = -7271763575775465174L;
14 |
15 | private Map additionalEntries = new HashMap<>();
16 | private List sections = new ArrayList<>();
17 |
18 | public Map getAdditionalEntries() {
19 | return additionalEntries;
20 | }
21 |
22 | public void setAdditionalEntries(Map additionalEntries) {
23 | this.additionalEntries = additionalEntries;
24 | }
25 |
26 | public List getSections() {
27 | return sections;
28 | }
29 |
30 | public void setSections(List sections) {
31 | this.sections = sections;
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return "Manifest [additionalEntries=" + additionalEntries + ", sections=" + sections + "]";
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/ManifestSection.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | /**
8 | * Manifest section
9 | */
10 | public class ManifestSection implements Serializable {
11 | private static final long serialVersionUID = 118641813298011799L;
12 |
13 | private String name;
14 | private Map entries = new HashMap<>();
15 |
16 | public ManifestSection() {
17 | super();
18 | }
19 |
20 | public ManifestSection(String name, Map entries) {
21 | super();
22 | this.name = name;
23 | this.entries = entries;
24 | }
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public void setName(String name) {
31 | this.name = name;
32 | }
33 |
34 | public Map getEntries() {
35 | return entries;
36 | }
37 |
38 | public void setEntries(Map entries) {
39 | this.entries = entries;
40 | }
41 |
42 | @Override
43 | public String toString() {
44 | return "ManifestSection [name=" + name + ", entries=" + entries + "]";
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/Platform.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import org.apache.commons.lang3.SystemUtils;
4 |
5 | /**
6 | * JavaPackager target platform
7 | */
8 | public enum Platform {
9 | auto,
10 | linux,
11 | mac,
12 | windows;
13 |
14 | public boolean isCurrentPlatform() {
15 | if (this == auto) return true;
16 | return this == getCurrentPlatform();
17 | }
18 |
19 | public static Platform getCurrentPlatform() {
20 | if (SystemUtils.IS_OS_WINDOWS) return windows;
21 | if (SystemUtils.IS_OS_LINUX) return linux;
22 | if (SystemUtils.IS_OS_MAC) return mac;
23 | return null;
24 | }
25 |
26 | public static Platform getPlatform(String platformString) {
27 | switch (platformString.toLowerCase()) {
28 | case "linux": return linux;
29 | case "darwin": return mac;
30 | case "windows": return windows;
31 | default: throw new IllegalArgumentException("Unknown platform " + platformString);
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/Registry.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | /**
8 | * Windows Registry entries to be created when installing using Setup
9 | */
10 | public class Registry implements Serializable {
11 | private static final long serialVersionUID = 8310081277297116023L;
12 |
13 | private List entries = new ArrayList<>();
14 |
15 | public Registry() {
16 | super();
17 | }
18 |
19 | public Registry(List entries) {
20 | super();
21 | this.entries = entries;
22 | }
23 |
24 | public List getEntries() {
25 | return entries;
26 | }
27 |
28 | public void setEntries(List entries) {
29 | this.entries = entries;
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return "Registry [entries=" + entries + "]";
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/RegistryEntry.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Windows Registry entry
7 | */
8 | public class RegistryEntry implements Serializable {
9 | private static final long serialVersionUID = 447936480111873679L;
10 |
11 | /**
12 | * Windows registry key: HKCU, HKLM, ...
13 | */
14 | private String key;
15 |
16 | /**
17 | * Windows Registry value name
18 | */
19 | private String valueName;
20 |
21 | /**
22 | * Windows Registry value type
23 | */
24 | private ValueType valueType = ValueType.REG_SZ;
25 |
26 | /**
27 | * Windows Registry value data
28 | */
29 | private String valueData = "";
30 |
31 | public RegistryEntry() {
32 | super();
33 | }
34 |
35 | public RegistryEntry(String key, String valueName, ValueType valueType, String valueData) {
36 | super();
37 | this.key = key;
38 | this.valueName = valueName;
39 | this.valueType = valueType;
40 | this.valueData = valueData;
41 | }
42 |
43 | public String getKey() {
44 | return key;
45 | }
46 |
47 | public void setKey(String key) {
48 | this.key = key;
49 | }
50 |
51 | public String getValueName() {
52 | return valueName;
53 | }
54 |
55 | public void setValueName(String valueName) {
56 | this.valueName = valueName;
57 | }
58 |
59 | public ValueType getValueType() {
60 | return valueType;
61 | }
62 |
63 | public void setValueType(ValueType valueType) {
64 | this.valueType = valueType;
65 | }
66 |
67 | public String getValueData() {
68 | return valueData;
69 | }
70 |
71 | public void setValueData(String valueData) {
72 | this.valueData = valueData;
73 | }
74 |
75 | public String getRoot() {
76 | return key.split(":")[0];
77 | }
78 |
79 | public String getSubkey() {
80 | String subkey = key.split(":")[1];
81 | return subkey.startsWith("/") ? subkey.substring(1) : subkey;
82 | }
83 |
84 | /**
85 | * Returns value type as Inno Setup expects
86 | * https://jrsoftware.org/ishelp/index.php?topic=registrysection
87 | * @return Value type converted to IS format
88 | */
89 | public String getValueTypeAsInnoSetupString() {
90 | switch(valueType) {
91 | case REG_BINARY: return "binary";
92 | case REG_DWORD: return "dword";
93 | case REG_EXPAND_SZ: return "expandsz";
94 | case REG_MULTI_SZ: return "multisz";
95 | case REG_QWORD: return "qword";
96 | case REG_SZ: return "string";
97 | default: return "none";
98 | }
99 | }
100 |
101 | /**
102 | * Returns value type as WIX Toolset expects
103 | * https://wixtoolset.org/documentation/manual/v3/xsd/wix/registryvalue.html
104 | */
105 | public String getValueTypeAsWIXToolsetString() {
106 | switch(valueType) {
107 | case REG_BINARY: return "binary";
108 | case REG_DWORD: return "integer";
109 | case REG_EXPAND_SZ: return "expandable";
110 | case REG_MULTI_SZ: return "multiString";
111 | case REG_QWORD: return "integer";
112 | case REG_SZ: return "string";
113 | default: return "none";
114 | }
115 | }
116 |
117 | @Override
118 | public String toString() {
119 | return "RegistryEntry [key=" + key + ", valueName=" + valueName + ", valueType=" + valueType + ", valueData="
120 | + valueData + "]";
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/Scripts.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.File;
4 | import java.io.Serializable;
5 |
6 | public class Scripts implements Serializable {
7 | private static final long serialVersionUID = 5665412825491635461L;
8 |
9 | private File bootstrap;
10 | private File preInstall;
11 | private File postInstall;
12 |
13 | public File getBootstrap() {
14 | return bootstrap;
15 | }
16 |
17 | public void setBootstrap(File bootstrap) {
18 | this.bootstrap = bootstrap;
19 | }
20 |
21 | public File getPreInstall() {
22 | return preInstall;
23 | }
24 |
25 | public void setPreInstall(File preInstall) {
26 | this.preInstall = preInstall;
27 | }
28 |
29 | public File getPostInstall() {
30 | return postInstall;
31 | }
32 |
33 | public void setPostInstall(File postInstall) {
34 | this.postInstall = postInstall;
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return "Scripts [bootstrap=" + bootstrap + ", preInstall=" + preInstall + ", postInstall=" + postInstall + "]";
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/SetupMode.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | /**
4 | * Windows Setup mode
5 | */
6 | public enum SetupMode {
7 | installForAllUsers,
8 | installForCurrentUser,
9 | askTheUser
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/Template.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | public class Template {
4 |
5 | private String name;
6 | private boolean bom = false;
7 |
8 | public Template() {}
9 |
10 | public Template(String name, boolean bom) {
11 | this.name = name;
12 | this.bom = bom;
13 | }
14 |
15 | public String getName() {
16 | return name;
17 | }
18 |
19 | public void setName(String name) {
20 | this.name = name;
21 | }
22 |
23 | public boolean isBom() {
24 | return bom;
25 | }
26 |
27 | public void setBom(boolean bom) {
28 | this.bom = bom;
29 | }
30 |
31 | @Override
32 | public String toString() {
33 | return "Template [name=" + name + ", bom=" + bom + "]";
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/ValueType.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | /**
4 | * Value type of Windows Registry entries.
5 | */
6 | public enum ValueType {
7 | REG_SZ,
8 | REG_EXPAND_SZ,
9 | REG_MULTI_SZ,
10 | REG_DWORD,
11 | REG_QWORD,
12 | REG_BINARY
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/WindowsExeCreationTool.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | public enum WindowsExeCreationTool {
4 | launch4j,
5 | why,
6 | winrun4j;
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/model/WindowsSigning.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.model;
2 |
3 | import java.io.File;
4 | import java.io.Serializable;
5 |
6 | import org.apache.commons.lang3.StringUtils;
7 |
8 | /**
9 | * Info needed for signing EXEs on Windows
10 | */
11 | public class WindowsSigning implements Serializable {
12 |
13 | private static final long serialVersionUID = 2559089741502151307L;
14 |
15 | private String storetype;
16 | private File keystore;
17 | private File certfile;
18 | private File keyfile;
19 | private String storepass;
20 | private String alias;
21 | private String keypass;
22 | private String alg;
23 |
24 | public String getStoretype() {
25 | return storetype;
26 | }
27 |
28 | public void setStoretype(String storetype) {
29 | this.storetype = storetype;
30 | }
31 |
32 | public File getKeystore() {
33 | return keystore;
34 | }
35 |
36 | public void setKeystore(File keystore) {
37 | this.keystore = keystore;
38 | }
39 |
40 | public File getCertfile() {
41 | return certfile;
42 | }
43 |
44 | public void setCertfile(File certfile) {
45 | this.certfile = certfile;
46 | }
47 |
48 | public File getKeyfile() {
49 | return keyfile;
50 | }
51 |
52 | public void setKeyfile(File keyfile) {
53 | this.keyfile = keyfile;
54 | }
55 |
56 | public String getStorepass() {
57 | return storepass;
58 | }
59 |
60 | public void setStorepass(String storepass) {
61 | this.storepass = storepass;
62 | }
63 |
64 | public String getAlias() {
65 | return alias;
66 | }
67 |
68 | public void setAlias(String alias) {
69 | this.alias = alias;
70 | }
71 |
72 | public String getKeypass() {
73 | return keypass;
74 | }
75 |
76 | public void setKeypass(String keypass) {
77 | this.keypass = keypass;
78 | }
79 |
80 | public String getAlg() {
81 | return alg;
82 | }
83 |
84 | public void setAlg(String alg) {
85 | this.alg = alg;
86 | }
87 |
88 | @Override
89 | public String toString() {
90 | String keypass = this.keypass != null ? StringUtils.repeat("*", this.keypass.length()) : "";
91 | String storepass = this.storepass != null ? StringUtils.repeat("*", this.storepass.length()) : "";
92 | return "WindowsSigning [storetype=" + storetype + ", keystore=" + keystore + ", certfile=" + certfile
93 | + ", keyfile=" + keyfile + ", storepass=" + storepass + ", alias=" + alias + ", keypass=" + keypass + ", alg=" + alg
94 | + "]";
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/AbstractCreateWindowsExe.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 |
5 | import io.github.fvarrui.javapackager.model.Platform;
6 | import io.github.fvarrui.javapackager.model.WindowsExeCreationTool;
7 | import io.github.fvarrui.javapackager.utils.FileUtils;
8 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
9 |
10 | public abstract class AbstractCreateWindowsExe extends ArtifactGenerator {
11 |
12 | private final File outputFolder;
13 | private File genericManifest;
14 | private File genericIcon;
15 | private File genericJar;
16 | private File genericExe;
17 |
18 | public AbstractCreateWindowsExe(WindowsExeCreationTool tool) {
19 | super(tool.toString());
20 | this.outputFolder = new File(Context.getContext().getBuildDir(), tool.toString());
21 | }
22 |
23 | public File getGenericManifest() {
24 | return genericManifest;
25 | }
26 |
27 | public void setGenericManifest(File genericManifest) {
28 | this.genericManifest = genericManifest;
29 | }
30 |
31 | public File getGenericIcon() {
32 | return genericIcon;
33 | }
34 |
35 | public void setGenericIcon(File genericIcon) {
36 | this.genericIcon = genericIcon;
37 | }
38 |
39 | public File getGenericJar() {
40 | return genericJar;
41 | }
42 |
43 | public void setGenericJar(File genericJar) {
44 | this.genericJar = genericJar;
45 | }
46 |
47 | public File getGenericExe() {
48 | return genericExe;
49 | }
50 |
51 | public void setGenericExe(File genericExe) {
52 | this.genericExe = genericExe;
53 | }
54 |
55 | public File getOutputFolder() {
56 | return outputFolder;
57 | }
58 |
59 | /**
60 | * Renames assets required for exe generation to avoid unsupported characters
61 | * (chinese, e.g.)
62 | *
63 | * @param packager Windows packager
64 | * @throws Exception Something went wrong
65 | */
66 | protected void createAssets(WindowsPackager packager) throws Exception {
67 |
68 | File manifestFile = packager.getManifestFile();
69 | File iconFile = packager.getIconFile();
70 | File jarFile = packager.getJarFile();
71 |
72 | FileUtils.mkdir(outputFolder);
73 |
74 | genericManifest = new File(outputFolder, "app.exe.manifest");
75 | genericIcon = new File(outputFolder, "app.ico");
76 | genericJar = new File(outputFolder, "app.jar");
77 | genericExe = new File(outputFolder, "app.exe");
78 |
79 | FileUtils.copyFileToFile(manifestFile, genericManifest);
80 | FileUtils.copyFileToFile(iconFile, genericIcon);
81 | FileUtils.copyFileToFile(jarFile, genericJar);
82 |
83 | }
84 |
85 | /**
86 | * Creates bootstrap script if needed
87 | * @param packager
88 | * @return
89 | * @throws Exception
90 | */
91 | protected File createBootstrapScript(WindowsPackager packager) throws Exception {
92 | File executable = packager.getExecutable();
93 |
94 | if (FileUtils.exists(packager.getScripts().getBootstrap())) {
95 |
96 | // generates startup VBS script file
97 | File vbsFile = new File(packager.getAppFolder(), packager.getName() + ".vbs");
98 | VelocityUtils.render(Platform.windows + "/startup.vbs.vtl", vbsFile, packager);
99 | executable = vbsFile;
100 |
101 | }
102 |
103 | return executable;
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/ArtifactGenerator.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 |
5 | import io.github.fvarrui.javapackager.utils.Logger;
6 |
7 |
8 | /**
9 | * Artifact generation base class
10 | */
11 | public abstract class ArtifactGenerator {
12 |
13 | private String artifactName;
14 |
15 | public ArtifactGenerator() {
16 | super();
17 | }
18 |
19 | public ArtifactGenerator(String artifactName) {
20 | super();
21 | this.artifactName = artifactName;
22 | }
23 |
24 | public boolean skip(T packager) {
25 | return false;
26 | }
27 |
28 | public String getArtifactName() {
29 | return artifactName;
30 | }
31 |
32 | public void setArtifactName(String artifactName) {
33 | this.artifactName = artifactName;
34 | }
35 |
36 | protected abstract File doApply(T packager) throws Exception;
37 |
38 | @SuppressWarnings("unchecked")
39 | public File apply(Packager packager) throws Exception {
40 | if (skip((T)packager)) {
41 | Logger.warn(getArtifactName() + " artifact generation skipped!");
42 | return null;
43 | }
44 | return doApply((T)packager);
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/Context.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import org.apache.commons.collections4.map.HashedMap;
9 |
10 | import io.github.fvarrui.javapackager.gradle.GradleContext;
11 | import io.github.fvarrui.javapackager.maven.MavenContext;
12 | import io.github.fvarrui.javapackager.model.Platform;
13 |
14 | /**
15 | * Building-tool context
16 | */
17 | public abstract class Context {
18 |
19 | public Context() {
20 | super();
21 |
22 | // building tool independent generators
23 | getInstallerGenerators(Platform.linux).add(new GenerateDeb());
24 | getInstallerGenerators(Platform.linux).add(new GenerateRpm());
25 | getInstallerGenerators(Platform.linux).add(new GenerateAppImage());
26 | getInstallerGenerators(Platform.mac).add(new GenerateDmg());
27 | getInstallerGenerators(Platform.mac).add(new GeneratePkg());
28 | getInstallerGenerators(Platform.windows).add(new GenerateSetup());
29 | getInstallerGenerators(Platform.windows).add(new GenerateMsm());
30 | getInstallerGenerators(Platform.windows).add(new GenerateMsi());
31 |
32 | }
33 |
34 | // common properties
35 |
36 | public abstract File getRootDir();
37 | public abstract File getBuildDir();
38 | public abstract T getLogger();
39 |
40 | // platform independent functions
41 |
42 | public abstract File createRunnableJar(Packager packager) throws Exception;
43 | public abstract File copyDependencies(Packager packager) throws Exception;
44 | public abstract File createTarball(Packager packager) throws Exception;
45 | public abstract File createZipball(Packager packager) throws Exception;
46 | public abstract File resolveLicense(Packager packager) throws Exception;
47 | public abstract File createWindowsExe(WindowsPackager packager) throws Exception;
48 |
49 | // installer producers
50 |
51 | private Map>> installerGeneratorsMap = new HashedMap<>();
52 |
53 | public List> getInstallerGenerators(Platform platform) {
54 | List> platformInstallers = installerGeneratorsMap.get(platform);
55 | if (platformInstallers == null) {
56 | platformInstallers = new ArrayList<>();
57 | installerGeneratorsMap.put(platform, platformInstallers);
58 | }
59 | return platformInstallers;
60 | }
61 |
62 | // static context
63 |
64 | private static Context> context;
65 |
66 | public static Context> getContext() {
67 | return context;
68 | }
69 |
70 | public static void setContext(Context> context) {
71 | Context.context = context;
72 | }
73 |
74 | public static boolean isMaven() {
75 | return context instanceof MavenContext;
76 | }
77 |
78 | public static boolean isGradle() {
79 | return context instanceof GradleContext;
80 | }
81 |
82 | public static MavenContext getMavenContext() {
83 | return (MavenContext) context;
84 | }
85 |
86 | public static GradleContext getGradleContext() {
87 | return (GradleContext) context;
88 | }
89 |
90 | public File getDefaultToolchain() {
91 | if (System.getenv("JAVA_HOME") != null) {
92 | return new File(System.getenv("JAVA_HOME")); // Use JAVA_HOME as fallback
93 | }
94 | return new File(System.getProperty("java.home"));
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWhy.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 |
5 | import io.github.fvarrui.javapackager.model.Platform;
6 | import io.github.fvarrui.javapackager.model.WindowsConfig;
7 | import io.github.fvarrui.javapackager.model.WindowsExeCreationTool;
8 | import io.github.fvarrui.javapackager.utils.FileUtils;
9 | import io.github.fvarrui.javapackager.utils.Logger;
10 | import io.github.fvarrui.javapackager.utils.RcEdit;
11 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
12 | import net.jsign.WindowsSigner;
13 |
14 | /**
15 | * Creates Windows executable with WinRun4j
16 | */
17 | public class CreateWindowsExeWhy extends AbstractCreateWindowsExe {
18 |
19 | public CreateWindowsExeWhy() {
20 | super(WindowsExeCreationTool.why);
21 | }
22 |
23 | @Override
24 | public boolean skip(WindowsPackager packager) {
25 |
26 | if (!packager.getPlatform().isCurrentPlatform()) {
27 | Logger.error(getArtifactName() + " cannot be generated with Why due to the target platform (" + packager.getPlatform() + ") is different from the execution platform (" + Platform.getCurrentPlatform() + ")!");
28 | return true;
29 | }
30 |
31 | return false;
32 | }
33 |
34 | @Override
35 | protected File doApply(WindowsPackager packager) throws Exception {
36 |
37 | File executable = packager.getExecutable();
38 | File manifestFile = packager.getManifestFile();
39 | File iconFile = packager.getIconFile();
40 | File appFolder = packager.getAppFolder();
41 | File jarFile = packager.getJarFile();
42 | WindowsConfig winConfig = packager.getWinConfig();
43 |
44 | if (winConfig.isWrapJar()) {
45 | Logger.warn("'wrapJar' property ignored when building EXE with " + getArtifactName());
46 | }
47 |
48 | createAssets(packager);
49 |
50 | // creates generic manifest
51 | FileUtils.copyFileToFile(manifestFile, getGenericManifest());
52 |
53 | // creates generic manifest
54 | FileUtils.copyFileToFile(iconFile, getGenericIcon());
55 |
56 | // creates generic exe
57 | FileUtils.copyResourceToFile("/windows/JavaLauncher.exe", getGenericExe(), packager.getAssetsDir());
58 |
59 | // generates ini file
60 | File genericIni = new File(getOutputFolder(), "launcher.ini");
61 | VelocityUtils.render("windows/why-ini.vtl", genericIni, packager);
62 | Logger.info("INI file generated in " + genericIni.getAbsolutePath() + "!");
63 |
64 | // set exe metadata with rcedit
65 | RcEdit rcedit = new RcEdit(getOutputFolder());
66 | rcedit.setIcon(getGenericExe(), getGenericIcon());
67 | rcedit.setManifest(getGenericExe(), getGenericManifest());
68 | rcedit.setFileVersion(getGenericExe(), winConfig.getFileVersion());
69 | rcedit.setProductVersion(getGenericExe(), winConfig.getProductVersion());
70 | rcedit.setVersionString(getGenericExe(), "FileDescription", winConfig.getFileDescription());
71 | rcedit.setVersionString(getGenericExe(), "CompanyName", winConfig.getCompanyName());
72 | rcedit.setVersionString(getGenericExe(), "InternalName", winConfig.getInternalName());
73 | rcedit.setVersionString(getGenericExe(), "OriginalFilename", winConfig.getOriginalFilename());
74 | rcedit.setVersionString(getGenericExe(), "ProductName", winConfig.getProductName());
75 |
76 | // copies JAR to app folder
77 | FileUtils.copyFileToFolder(jarFile, appFolder);
78 |
79 | // copies ini file to app folder
80 | FileUtils.copyFileToFolder(genericIni, appFolder);
81 |
82 | // copies exe file to app folder with apps name
83 | FileUtils.copyFileToFile(getGenericExe(), executable);
84 |
85 | return createBootstrapScript(packager);
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWinRun4j.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 | import java.nio.file.Path;
5 | import java.util.Arrays;
6 | import java.util.Optional;
7 |
8 | import net.jsign.WindowsSigner;
9 | import org.apache.commons.lang3.StringUtils;
10 |
11 | import io.github.fvarrui.javapackager.model.Arch;
12 | import io.github.fvarrui.javapackager.model.Platform;
13 | import io.github.fvarrui.javapackager.model.WindowsConfig;
14 | import io.github.fvarrui.javapackager.model.WindowsExeCreationTool;
15 | import io.github.fvarrui.javapackager.utils.FileUtils;
16 | import io.github.fvarrui.javapackager.utils.JDKUtils;
17 | import io.github.fvarrui.javapackager.utils.Logger;
18 | import io.github.fvarrui.javapackager.utils.RcEdit;
19 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
20 |
21 | /**
22 | * Creates Windows executable with WinRun4j
23 | */
24 | public class CreateWindowsExeWinRun4j extends AbstractCreateWindowsExe {
25 |
26 | private static final String [] JVM_DLL_PATHS = {
27 | "bin/client/jvm.dll",
28 | "bin/server/jvm.dll"
29 | };
30 |
31 | public CreateWindowsExeWinRun4j() {
32 | super(WindowsExeCreationTool.winrun4j);
33 | }
34 |
35 | @Override
36 | public boolean skip(WindowsPackager packager) {
37 |
38 | if (!packager.getPlatform().isCurrentPlatform()) {
39 | Logger.error(getArtifactName() + " cannot be generated with WinRun4J due to the target platform (" + packager.getPlatform() + ") is different from the execution platform (" + Platform.getCurrentPlatform() + ")!");
40 | return true;
41 | }
42 |
43 | return false;
44 | }
45 |
46 | @Override
47 | protected File doApply(WindowsPackager packager) throws Exception {
48 |
49 | String name = packager.getName();
50 | File executable = packager.getExecutable();
51 | File jarFile = packager.getJarFile();
52 | File manifestFile = packager.getManifestFile();
53 | File iconFile = packager.getIconFile();
54 | File appFolder = packager.getAppFolder();
55 | File jreDestinationFolder = packager.getJreDestinationFolder();
56 | boolean bundleJre = packager.getBundleJre();
57 | String vmLocation = packager.getWinConfig().getVmLocation();
58 | WindowsConfig winConfig = packager.getWinConfig();
59 | Arch arch = packager.getArch();
60 |
61 | if (winConfig.isWrapJar()) {
62 | Logger.warn("'wrapJar' property ignored when building EXE with " + getArtifactName());
63 | }
64 |
65 | createAssets(packager);
66 |
67 | // creates generic manifest
68 | FileUtils.copyFileToFile(manifestFile, getGenericManifest());
69 |
70 | // creates generic manifest
71 | FileUtils.copyFileToFile(iconFile, getGenericIcon());
72 |
73 | // checks if target architecture matches JRE arch
74 | if (bundleJre && !JDKUtils.isValidJRE(Platform.windows, arch, packager.getJreDestinationFolder())) {
75 | throw new Exception("Bundled JRE must match " + Platform.windows + " " + arch);
76 | }
77 |
78 | // creates generic exe
79 | if (arch == Arch.x86) {
80 | FileUtils.copyResourceToFile("/windows/WinRun4J.exe", getGenericExe());
81 | } else {
82 | FileUtils.copyResourceToFile("/windows/WinRun4J64.exe", getGenericExe());
83 | }
84 |
85 | // uses vmLocation only if a JRE is bundled
86 | if (bundleJre) {
87 |
88 | // checks if vmLocation property is specified in winConfig
89 | if (!StringUtils.isBlank(vmLocation)) {
90 |
91 | // checks if specified vmLocation exists
92 | if (!new File(jreDestinationFolder, vmLocation).exists()) {
93 | throw new Exception("VM location '" + vmLocation + "' does not exist");
94 | }
95 |
96 | vmLocation = vmLocation.replaceAll("/", "\\\\");
97 |
98 | } else {
99 |
100 | // searchs for a valid jvm.dll file in JRE
101 | Optional jvmDllFile = Arrays.asList(JVM_DLL_PATHS)
102 | .stream()
103 | .map(path -> new File(jreDestinationFolder, path))
104 | .filter(file -> file.exists())
105 | .findFirst();
106 |
107 | // checks if found jvm.dll
108 | if (!jvmDllFile.isPresent()) {
109 | throw new Exception("jvm.dll not found!");
110 | }
111 |
112 | // relativize jvm.dll path to JRE, in order to use it a "vm.location"
113 | Path jreDestinationPath = jreDestinationFolder.toPath();
114 | Path jvmDllPath = jvmDllFile.get().toPath();
115 | vmLocation = jreDestinationPath.relativize(jvmDllPath).toString();
116 |
117 | }
118 |
119 | // sets vmLocation in winConfig, so it will be used when rendering INI file
120 | packager.getWinConfig().setVmLocation(vmLocation);
121 |
122 | Logger.info("Using 'vmLocation=" + vmLocation + "'!");
123 |
124 | }
125 |
126 | // set exe metadata with rcedit
127 | RcEdit rcedit = new RcEdit(getOutputFolder());
128 | rcedit.setIcon(getGenericExe(), getGenericIcon());
129 | rcedit.setManifest(getGenericExe(), getGenericManifest());
130 | rcedit.setFileVersion(getGenericExe(), winConfig.getFileVersion());
131 | rcedit.setProductVersion(getGenericExe(), winConfig.getProductVersion());
132 | rcedit.setVersionString(getGenericExe(), "FileDescription", winConfig.getFileDescription());
133 | rcedit.setVersionString(getGenericExe(), "CompanyName", winConfig.getCompanyName());
134 | rcedit.setVersionString(getGenericExe(), "InternalName", winConfig.getInternalName());
135 | rcedit.setVersionString(getGenericExe(), "OriginalFilename", winConfig.getOriginalFilename());
136 | rcedit.setVersionString(getGenericExe(), "ProductName", winConfig.getProductName());
137 |
138 | // copies JAR to libs folder
139 | FileUtils.copyFileToFolder(jarFile, appFolder);
140 |
141 | // generates ini file
142 | File genericIni = new File(getOutputFolder(), "app.ini");
143 | VelocityUtils.render("windows/ini.vtl", genericIni, packager);
144 | Logger.info("INI file generated in " + genericIni.getAbsolutePath() + "!");
145 |
146 | // copies ini file to app folder
147 | File iniFile = new File(appFolder, name + ".ini");
148 | FileUtils.copyFileToFile(genericIni, iniFile);
149 |
150 | // copies exe file to app folder with apps name
151 | FileUtils.copyFileToFile(getGenericExe(), executable);
152 |
153 | return createBootstrapScript(packager);
154 | }
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateAppImage.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import io.github.fvarrui.javapackager.model.Platform;
4 | import io.github.fvarrui.javapackager.utils.CommandUtils;
5 | import io.github.fvarrui.javapackager.utils.FileUtils;
6 | import io.github.fvarrui.javapackager.utils.Logger;
7 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
8 | import org.apache.commons.lang3.SystemUtils;
9 |
10 | import java.io.File;
11 | import java.io.IOException;
12 |
13 | public class GenerateAppImage extends ArtifactGenerator {
14 |
15 | private static final int IMAGETOOL_VERSION = 13;
16 | private static final String IMAGETOOL_URL = "https://github.com/AppImage/AppImageKit/releases/download/" + IMAGETOOL_VERSION + "/appimagetool-%s.AppImage";
17 |
18 | public GenerateAppImage() {
19 | super("AppImage");
20 | }
21 |
22 | @Override
23 | public boolean skip(LinuxPackager packager) {
24 |
25 | if (!packager.getLinuxConfig().isGenerateAppImage()) {
26 | return true;
27 | }
28 |
29 | if (!packager.getPlatform().isCurrentPlatform() && !packager.isForceInstaller()) {
30 | Logger.warn(getArtifactName() + " cannot be generated due to the target platform (" + packager.getPlatform() + ") is different from the execution platform (" + Platform.getCurrentPlatform() + ")!");
31 | return true;
32 | }
33 |
34 | return false;
35 |
36 | }
37 |
38 | @Override
39 | protected File doApply(LinuxPackager packager) throws Exception {
40 |
41 | File appFolder = packager.getAppFolder();
42 | File outputFolder = packager.getOutputDirectory();
43 | String name = packager.getName();
44 | File executable = packager.getExecutable();
45 | File assetsFolder = packager.getAssetsFolder();
46 | File iconFile = packager.getIconFile();
47 |
48 | // output AppImage file
49 | File appImage = new File(outputFolder, name + ".AppImage");
50 |
51 | // AppDir folder
52 | File appDir = new File(assetsFolder, "AppDir");
53 |
54 | // gets/downloads AppImage tool
55 | Logger.info("Getting appimagetool...");
56 | File appImageTool = getAppImageTool(packager);
57 | Logger.info("App image tool found! " + appImageTool);
58 |
59 | // copies app folder to AppDir/usr/bin
60 | FileUtils.copyFolderContentToFolder(appFolder, new File(appDir, "usr/bin"));
61 |
62 | // generates AppImage desktop file from velocity template
63 | File desktopFile = new File(appDir, name + ".desktop");
64 | VelocityUtils.render("linux/desktop-appimage.vtl", desktopFile, packager);
65 | Logger.info("Desktop file rendered in " + desktopFile.getAbsolutePath());
66 |
67 | // creates AppRun symlink to startup script
68 | Logger.info("Creating AppRun symlink to startup script...");
69 | File appRun = new File(appDir, "AppRun");
70 | FileUtils.createSymlink(appRun, new File("usr/bin", executable.getName()));
71 |
72 | // creates AppRun symlink to startup script
73 | Logger.info("Copying icon to AppDir ...");
74 | FileUtils.copyFileToFolder(iconFile, appDir);
75 |
76 | // runs appimagetool on appFolder
77 | Logger.info("Running appimagetool on " + appFolder);
78 | CommandUtils.execute(
79 | appImageTool,
80 | "--appimage-extract-and-run",
81 | appDir,
82 | appImage
83 | );
84 |
85 | Logger.info("Setting execution permissions to " + appImage);
86 | appImage.setExecutable(true);
87 |
88 | return appImage;
89 | }
90 |
91 | private File getAppImageTool(LinuxPackager packager) throws Exception {
92 | File assetsFolder = packager.getAssetsFolder();
93 | File appImageTool = new File(assetsFolder, "appimagetool");
94 | if (!appImageTool.exists()) {
95 | String imageToolUrl = String.format(IMAGETOOL_URL, getOSArch());
96 | try {
97 | FileUtils.downloadFromUrl(imageToolUrl, appImageTool);
98 | } catch (IOException e) {
99 | throw new Exception("An error occurred while downloading appimagetool from " + imageToolUrl + " for " + getOSArch() + "! It may be a network problem or the url " + imageToolUrl + " is not valid!", e);
100 | }
101 | appImageTool.setExecutable(true);
102 | }
103 | return appImageTool;
104 | }
105 |
106 | private String getOSArch() {
107 | switch (SystemUtils.OS_ARCH) {
108 | case "amd64":
109 | return "x86_64";
110 | case "x86":
111 | case "i386":
112 | return "i686";
113 | }
114 | return SystemUtils.OS_ARCH;
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateDmg.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import static io.github.fvarrui.javapackager.utils.CommandUtils.execute;
4 | import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
5 |
6 | import java.io.File;
7 | import java.util.Arrays;
8 | import java.util.Optional;
9 |
10 | import org.apache.commons.lang3.StringUtils;
11 |
12 | import io.github.fvarrui.javapackager.model.MacConfig;
13 | import io.github.fvarrui.javapackager.model.Platform;
14 | import io.github.fvarrui.javapackager.utils.FileUtils;
15 | import io.github.fvarrui.javapackager.utils.Logger;
16 | import io.github.fvarrui.javapackager.utils.ThreadUtils;
17 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
18 |
19 | /**
20 | * Creates a DMG image file including all app folder's content only for MacOS so
21 | * app could be easily distributed
22 | */
23 | public class GenerateDmg extends ArtifactGenerator {
24 |
25 | public GenerateDmg() {
26 | super("DMG image");
27 | }
28 |
29 | @Override
30 | public boolean skip(MacPackager packager) {
31 |
32 | if (!packager.getMacConfig().isGenerateDmg()) {
33 | return true;
34 | }
35 |
36 | if (!packager.getPlatform().isCurrentPlatform() && !packager.isForceInstaller()) {
37 | Logger.warn(getArtifactName() + " cannot be generated due to the target platform (" + packager.getPlatform() + ") is different from the execution platform (" + Platform.getCurrentPlatform() + ")!");
38 | return true;
39 | }
40 |
41 | return false;
42 | }
43 |
44 | @Override
45 | protected File doApply(MacPackager packager) throws Exception {
46 |
47 | File appFolder = packager.getAppFolder();
48 | File assetsFolder = packager.getAssetsFolder();
49 | String name = packager.getName();
50 | File outputDirectory = packager.getOutputDirectory();
51 | File iconFile = packager.getIconFile();
52 | String version = packager.getVersion();
53 | MacConfig macConfig = packager.getMacConfig();
54 |
55 | // sets volume name if blank
56 | String volumeName = defaultIfBlank(macConfig.getVolumeName(), name);
57 |
58 | // removes whitespaces from volume name
59 | if (StringUtils.containsWhitespace(volumeName)) {
60 | volumeName = volumeName.replaceAll(" ", "");
61 | Logger.warn("Whitespaces has been removed from volume name: " + volumeName);
62 | }
63 |
64 | // final dmg file
65 | File dmgFile = new File(outputDirectory, name + "_" + version + ".dmg");
66 |
67 | // temp dmg file
68 | File tempDmgFile = new File(assetsFolder, dmgFile.getName());
69 |
70 | // mount dir
71 | File mountFolder = new File("/Volumes/" + volumeName);
72 |
73 | // copies background file
74 | Logger.info("Copying background image");
75 | File backgroundFolder = FileUtils.mkdir(appFolder, ".background");
76 | File backgroundFile = new File(backgroundFolder, "background.png");
77 | if (macConfig.getBackgroundImage() != null)
78 | FileUtils.copyFileToFile(macConfig.getBackgroundImage(), backgroundFile);
79 | else
80 | FileUtils.copyResourceToFile("/mac/background.png", backgroundFile);
81 |
82 | // copies volume icon
83 | Logger.info("Copying icon file: " + iconFile.getAbsolutePath());
84 | File volumeIcon = (macConfig.getVolumeIcon() != null) ? macConfig.getVolumeIcon() : iconFile;
85 | FileUtils.copyFileToFile(volumeIcon, new File(appFolder, ".VolumeIcon.icns"));
86 |
87 | // creates image
88 | Logger.info("Creating image: " + tempDmgFile.getAbsolutePath());
89 | String osArchitecture = System.getProperty("os.arch");
90 | boolean isAarch64 = osArchitecture.equalsIgnoreCase("aarch64");
91 | String fileSystem = isAarch64 ? "APFS" : "HFS+";
92 | Logger.warn(osArchitecture + " architecture detected. Using " + fileSystem + " filesystem");
93 | execute("hdiutil", "create", "-srcfolder", appFolder, "-volname", volumeName, "-ov", "-fs", fileSystem, "-format", "UDRW", tempDmgFile);
94 |
95 | if (mountFolder.exists()) {
96 | Logger.info("Unmounting volume: " + mountFolder);
97 | execute("hdiutil", "detach", mountFolder);
98 | }
99 |
100 | // mounts image
101 | Logger.info("Mounting image: " + tempDmgFile.getAbsolutePath());
102 | String result = execute("hdiutil", "attach", "-readwrite", "-noverify", "-noautoopen", tempDmgFile);
103 | Optional optDeviceName = Arrays.stream(result.split("\n"))
104 | .filter(s -> s.contains(mountFolder.getAbsolutePath()))
105 | .map(StringUtils::normalizeSpace)
106 | .map(s -> s.split(" ")[0])
107 | .findFirst();
108 | optDeviceName.ifPresent(deviceName -> Logger.info("- Device name: " + deviceName));
109 |
110 | // pause to prevent occasional "Can't get disk" (-1728) issues
111 | // https://github.com/seltzered/create-dmg/commit/5fe7802917bb85b40c0630b026d33e421db914ea
112 | ThreadUtils.sleep(2000L);
113 |
114 | // creates a symlink to Applications folder
115 | Logger.info("Creating Applications link");
116 | File targetFolder = new File("/Applications");
117 | File linkFile = new File(mountFolder, "Applications");
118 | FileUtils.createSymlink(linkFile, targetFolder);
119 |
120 | // renders applescript
121 | Logger.info("Rendering DMG customization applescript ... ");
122 | File applescriptFile = new File(assetsFolder, "customize-dmg.applescript");
123 | VelocityUtils.render("/mac/customize-dmg.applescript.vtl", applescriptFile, packager);
124 | Logger.info("Applescript rendered in " + applescriptFile.getAbsolutePath() + "!");
125 |
126 | // runs applescript
127 | Logger.info("Running applescript");
128 | execute("/usr/bin/osascript", applescriptFile, volumeName);
129 |
130 | // makes sure it's not world writeable and user readable
131 | Logger.info("Fixing permissions...");
132 | execute("chmod", "-Rf", "u+r,go-w", mountFolder);
133 |
134 | if (!isAarch64) {
135 | // makes the top window open itself on mount:
136 | Logger.info("Blessing ...");
137 | try {
138 | execute("bless", "--folder", mountFolder, "--openfolder", mountFolder); }
139 | catch (Exception e){
140 | Logger.warn("Error blessing " + mountFolder + " due to: " + e.getMessage());
141 | }
142 | }
143 |
144 | // tells the volume that it has a special file attribute
145 | execute("SetFile", "-a", "C", mountFolder);
146 |
147 | // unmounts
148 | Logger.info("Unmounting volume: " + mountFolder);
149 | execute("hdiutil", "detach", mountFolder);
150 |
151 | // compress image
152 | Logger.info("Compressing disk image...");
153 | execute("hdiutil", "convert", tempDmgFile, "-ov", "-format", "UDZO", "-imagekey", "zlib-level=9", "-o", dmgFile);
154 | tempDmgFile.delete();
155 |
156 | // checks if dmg file was created
157 | if (!dmgFile.exists()) {
158 | throw new Exception(getArtifactName() + " generation failed!");
159 | }
160 |
161 | return dmgFile;
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsi.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import static io.github.fvarrui.javapackager.utils.CommandUtils.execute;
4 |
5 | import java.io.File;
6 |
7 | import io.github.fvarrui.javapackager.model.Platform;
8 | import io.github.fvarrui.javapackager.utils.Logger;
9 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
10 | import io.github.fvarrui.javapackager.utils.XMLUtils;
11 | import net.jsign.WindowsSigner;
12 |
13 | /**
14 | * Creates an MSI file including all app folder's content only for
15 | * Windows so app could be easily distributed
16 | */
17 | public class GenerateMsi extends ArtifactGenerator {
18 |
19 | public GenerateMsi() {
20 | super("MSI installer");
21 | }
22 |
23 | @Override
24 | public boolean skip(WindowsPackager packager) {
25 |
26 | if (!packager.getWinConfig().isGenerateMsi()) {
27 | return true;
28 | }
29 |
30 | if (!packager.getPlatform().isCurrentPlatform() && !packager.isForceInstaller()) {
31 | Logger.warn(getArtifactName() + " cannot be generated due to the target platform (" + packager.getPlatform() + ") is different from the execution platform (" + Platform.getCurrentPlatform() + ")!");
32 | return true;
33 | }
34 |
35 | return false;
36 | }
37 |
38 | @Override
39 | protected File doApply(WindowsPackager packager) throws Exception {
40 |
41 | File msmFile = new GenerateMsm().doApply(packager);
42 | Logger.info("MSM file generated in " + msmFile);
43 |
44 | File assetsFolder = packager.getAssetsFolder();
45 | String name = packager.getName();
46 | File outputDirectory = packager.getOutputDirectory();
47 | String version = packager.getVersion();
48 |
49 | // generates WXS file from velocity template
50 | File wxsFile = new File(assetsFolder, name + ".wxs");
51 | VelocityUtils.render("windows/wxs.vtl", wxsFile, packager);
52 | Logger.info("WXS file generated in " + wxsFile + "!");
53 |
54 | // prettify wxs
55 | XMLUtils.prettify(wxsFile);
56 |
57 | // candle wxs file
58 | Logger.info("Compiling file " + wxsFile);
59 | File wixobjFile = new File(assetsFolder, name + ".wixobj");
60 | execute("candle", "-out", wixobjFile, wxsFile);
61 | Logger.info("WIXOBJ file generated in " + wixobjFile + "!");
62 |
63 | // lighting wxs file
64 | Logger.info("Linking file " + wixobjFile);
65 | File msiFile = new File(outputDirectory, name + "_" + version + ".msi");
66 | execute("light", "-sw1076", "-spdb", "-out", msiFile, wixobjFile);
67 |
68 | // setup file
69 | if (!msiFile.exists()) {
70 | throw new Exception("MSI installer file generation failed!");
71 | }
72 |
73 | // sign installer
74 | WindowsSigner.sign(msiFile, packager.getDisplayName(), packager.getUrl(), packager.getWinConfig().getSigning());
75 |
76 | return msiFile;
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsm.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 |
5 | import io.github.fvarrui.javapackager.model.Platform;
6 | import io.github.fvarrui.javapackager.utils.CommandUtils;
7 | import io.github.fvarrui.javapackager.utils.Logger;
8 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
9 | import io.github.fvarrui.javapackager.utils.XMLUtils;
10 |
11 | /**
12 | * Creates an MSI file including all app folder's content only for Windows so app
13 | * could be easily distributed
14 | */
15 | public class GenerateMsm extends ArtifactGenerator {
16 |
17 | public GenerateMsm() {
18 | super("MSI merge module");
19 | }
20 |
21 | @Override
22 | public boolean skip(WindowsPackager packager) {
23 |
24 | if (!packager.getWinConfig().isGenerateMsm() && !packager.getWinConfig().isGenerateMsi()) {
25 | return true;
26 | }
27 |
28 | if (!packager.getPlatform().isCurrentPlatform() && !packager.isForceInstaller()) {
29 | Logger.warn(getArtifactName() + " cannot be generated due to the target platform (" + packager.getPlatform() + ") is different from the execution platform (" + Platform.getCurrentPlatform() + ")!");
30 | return true;
31 | }
32 |
33 | return false;
34 | }
35 |
36 | @Override
37 | protected File doApply(WindowsPackager packager) throws Exception {
38 |
39 | if (packager.getMsmFile() != null) {
40 | return packager.getMsmFile();
41 | }
42 |
43 | File assetsFolder = packager.getAssetsFolder();
44 | String name = packager.getName();
45 | File outputDirectory = packager.getOutputDirectory();
46 | String version = packager.getVersion();
47 |
48 | // generates WXS file from velocity template
49 | File wxsFile = new File(assetsFolder, name + ".msm.wxs");
50 | VelocityUtils.render("windows/msm.wxs.vtl", wxsFile, packager);
51 | Logger.info("WXS file generated in " + wxsFile + "!");
52 |
53 | // prettify wxs
54 | XMLUtils.prettify(wxsFile);
55 |
56 | // candle wxs file
57 | Logger.info("Compiling file " + wxsFile);
58 | File wixobjFile = new File(assetsFolder, name + ".msm.wixobj");
59 | CommandUtils.execute("candle", "-out", wixobjFile, wxsFile);
60 | Logger.info("WIXOBJ file generated in " + wixobjFile + "!");
61 |
62 | // lighting wxs file
63 | Logger.info("Linking file " + wixobjFile);
64 | File msmFile = new File(outputDirectory, name + "_" + version + ".msm");
65 | CommandUtils.execute("light", "-sw1076", "-spdb", "-out", msmFile, wixobjFile);
66 |
67 | // setup file
68 | if (!msmFile.exists()) {
69 | throw new Exception("MSI installer file generation failed!");
70 | }
71 |
72 | packager.setMsmFile(msmFile);
73 |
74 | return msmFile;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/GeneratePkg.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 |
5 | import io.github.fvarrui.javapackager.model.Platform;
6 | import io.github.fvarrui.javapackager.utils.CommandUtils;
7 | import io.github.fvarrui.javapackager.utils.Logger;
8 |
9 | /**
10 | * Creates a PKG installer file including all app folder's content only for MacOS so
11 | * app could be easily distributed
12 | */
13 | public class GeneratePkg extends ArtifactGenerator {
14 |
15 | public GeneratePkg() {
16 | super("PKG installer");
17 | }
18 |
19 | @Override
20 | public boolean skip(MacPackager packager) {
21 |
22 | if (!packager.getMacConfig().isGeneratePkg()) {
23 | return true;
24 | }
25 |
26 | if (!packager.getPlatform().isCurrentPlatform() && !packager.isForceInstaller()) {
27 | Logger.warn(getArtifactName() + " cannot be generated due to the target platform (" + packager.getPlatform() + ") is different from the execution platform (" + Platform.getCurrentPlatform() + ")!");
28 | return true;
29 | }
30 |
31 | return false;
32 | }
33 |
34 | @Override
35 | protected File doApply(MacPackager packager) throws Exception {
36 |
37 | File appFile = packager.getAppFile();
38 | String name = packager.getName();
39 | File outputDirectory = packager.getOutputDirectory();
40 | String version = packager.getVersion();
41 |
42 | File pkgFile = new File(outputDirectory, name + "_" + version + ".pkg");
43 |
44 | // invokes pkgbuild command
45 | CommandUtils.execute("pkgbuild", "--install-location", "/Applications", "--component", appFile, pkgFile);
46 |
47 | // checks if pkg file was created
48 | if (!pkgFile.exists()) {
49 | throw new Exception(getArtifactName() + " generation failed!");
50 | }
51 |
52 | return pkgFile;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateRpm.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.security.NoSuchAlgorithmException;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 | import java.util.Objects;
9 |
10 | import org.redline_rpm.Builder;
11 | import org.redline_rpm.header.Architecture;
12 | import org.redline_rpm.header.Os;
13 | import org.redline_rpm.header.RpmType;
14 |
15 | import io.github.fvarrui.javapackager.utils.FileUtils;
16 | import io.github.fvarrui.javapackager.utils.Logger;
17 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
18 |
19 | /**
20 | * Creates a RPM package file including all app folder's content only for
21 | * GNU/Linux so app could be easily distributed on Gradle context
22 | */
23 | public class GenerateRpm extends ArtifactGenerator {
24 |
25 | public GenerateRpm() {
26 | super("RPM package");
27 | }
28 |
29 | @Override
30 | public boolean skip(LinuxPackager packager) {
31 | return !packager.getLinuxConfig().isGenerateRpm();
32 | }
33 |
34 | @Override
35 | protected File doApply(LinuxPackager packager) throws Exception {
36 |
37 | File appFolder = packager.getAppFolder();
38 | String name = packager.getName();
39 | String version = packager.getVersion().replaceAll("-", "_");
40 | String description = packager.getDescription();
41 | String organizationName = packager.getOrganizationName();
42 | File outputDirectory = packager.getOutputDirectory();
43 | File executable = packager.getExecutable();
44 | File assetsFolder = packager.getAssetsFolder();
45 | String jreDirectoryName = packager.getJreDirectoryName();
46 | Architecture arch = packager.getArch().toRpmArchitecture();
47 | File mimeXmlFile = packager.getMimeXmlFile();
48 | String installationPath = packager.getLinuxConfig().getInstallationPath();
49 | String appPath = installationPath + "/" + name;
50 |
51 | // generates desktop file from velocity template
52 | File desktopFile = new File(assetsFolder, name + ".desktop");
53 | VelocityUtils.render("linux/desktop.vtl", desktopFile, packager);
54 | Logger.info("Desktop file rendered in " + desktopFile.getAbsolutePath());
55 |
56 | // copies desktop file to app
57 | FileUtils.copyFileToFolder(desktopFile, appFolder);
58 |
59 | // creates RPM builder
60 | Builder builder = new Builder();
61 | builder.setType(RpmType.BINARY);
62 | builder.setPlatform(arch, Os.LINUX);
63 | builder.setPackage(name, version, "1");
64 | builder.setPackager(organizationName);
65 | builder.setDescription(description);
66 | builder.setPrefixes(installationPath);
67 |
68 | // list of files which needs execution permissions
69 | List executionPermissions = new ArrayList<>();
70 | executionPermissions.add(executable);
71 | executionPermissions.add(new File(appFolder, jreDirectoryName + "/bin/java"));
72 | executionPermissions.add(new File(appFolder, jreDirectoryName + "/lib/jspawnhelper"));
73 |
74 | // add all app files
75 | addDirectory(builder, installationPath, appFolder, executionPermissions);
76 |
77 | // link to desktop file
78 | addLink(builder, "/usr/share/applications/" + desktopFile.getName(), appPath + "/" + desktopFile.getName());
79 |
80 | // copy and link to mime.xml file
81 | if (mimeXmlFile != null) {
82 | FileUtils.copyFileToFolder(mimeXmlFile, appFolder);
83 | addLink(builder, "/usr/share/mime/packages/" + mimeXmlFile.getName(), appPath + "/" + mimeXmlFile.getName());
84 | }
85 |
86 | // link to binary
87 | addLink(builder, "/usr/local/bin/" + executable.getName(), appPath + "/" + executable.getName());
88 |
89 | // add all app files
90 | addDirectory(builder, installationPath, appFolder, executionPermissions);
91 |
92 | // build RPM file
93 | builder.build(outputDirectory);
94 |
95 | // renames generated RPM file if created
96 | String suffix = "-1." + arch + ".rpm";
97 | File originalRpm = new File(outputDirectory, name + "-" + version + suffix);
98 | File rpm = null;
99 | if (originalRpm.exists()) {
100 | rpm = new File(outputDirectory, name + "_" + version + ".rpm");
101 | if (rpm.exists()) rpm.delete();
102 | FileUtils.rename(originalRpm, rpm.getName());
103 | }
104 |
105 | return rpm;
106 | }
107 |
108 | private void addLink(Builder builder, String path, String target) throws NoSuchAlgorithmException, IOException {
109 | Logger.info("Adding link '" + path + "' to RPM builder targeting '" + target + "'");
110 | builder.addLink(path, target);
111 | }
112 |
113 | private void addFile(Builder builder, String rootPath, File file, int mode) throws NoSuchAlgorithmException, IOException {
114 | String filePath = rootPath + "/" + file.getName();
115 | Logger.info("Adding file '" + file + "' to RPM builder as '" + filePath + "'");
116 | builder.addFile(filePath, file, mode);
117 | }
118 |
119 | private void addDirectory(Builder builder, String parentPath, File directory, List executionPermissions) throws NoSuchAlgorithmException, IOException {
120 | String dirPath = parentPath + "/" + directory.getName();
121 | Logger.info("Adding directory '" + directory + "' to RPM builder as '" + dirPath + "'");
122 | builder.addDirectory(dirPath);
123 | for (File f : Objects.requireNonNull(directory.listFiles())) {
124 | if (f.isDirectory())
125 | addDirectory(builder, dirPath, f, executionPermissions);
126 | else {
127 | addFile(builder, dirPath, f, executionPermissions.contains(f) ? 0755 : 0644);
128 | }
129 | }
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateSetup.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 |
5 | import io.github.fvarrui.javapackager.model.Platform;
6 | import io.github.fvarrui.javapackager.utils.CommandUtils;
7 | import io.github.fvarrui.javapackager.utils.FileUtils;
8 | import io.github.fvarrui.javapackager.utils.Logger;
9 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
10 | import net.jsign.WindowsSigner;
11 |
12 | /**
13 | * Creates a Setup file including all app folder's content only for
14 | * Windows so app could be easily distributed
15 | */
16 | public class GenerateSetup extends ArtifactGenerator {
17 |
18 | public GenerateSetup() {
19 | super("Setup installer");
20 | }
21 |
22 | @Override
23 | public boolean skip(WindowsPackager packager) {
24 |
25 | if (!packager.getWinConfig().isGenerateSetup()) {
26 | return true;
27 | }
28 |
29 | if (!packager.getPlatform().isCurrentPlatform() && !packager.isForceInstaller()) {
30 | Logger.warn(getArtifactName() + " cannot be generated due to the target platform (" + packager.getPlatform() + ") is different from the execution platform (" + Platform.getCurrentPlatform() + ")!");
31 | return true;
32 | }
33 |
34 | return false;
35 | }
36 |
37 | @Override
38 | protected File doApply(WindowsPackager packager) throws Exception {
39 |
40 | File iconFile = packager.getIconFile();
41 | File assetsFolder = packager.getAssetsFolder();
42 | String name = packager.getName();
43 | File outputDirectory = packager.getOutputDirectory();
44 | String version = packager.getVersion();
45 |
46 | // copies ico file to assets folder
47 | FileUtils.copyFileToFolder(iconFile, assetsFolder);
48 |
49 | // generates iss file from velocity template
50 | File issFile = new File(assetsFolder, name + ".iss");
51 | VelocityUtils.render("windows/iss.vtl", issFile, packager);
52 |
53 | // generates Windows installer with inno setup command line compiler
54 | CommandUtils.execute("iscc", "/O" + outputDirectory.getAbsolutePath(), "/F" + name + "_" + version, issFile);
55 |
56 | // setup file
57 | File setupFile = new File(outputDirectory, name + "_" + version + ".exe");
58 | if (!setupFile.exists()) {
59 | throw new Exception("Windows setup file generation failed!");
60 | }
61 |
62 | // sign installer
63 | WindowsSigner.sign(setupFile, packager.getDisplayName(), packager.getUrl(), packager.getWinConfig().getSigning());
64 |
65 | return setupFile;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/LinuxPackager.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 | import java.util.Arrays;
5 | import java.util.stream.Collectors;
6 |
7 | import org.apache.commons.lang3.StringUtils;
8 |
9 | import io.github.fvarrui.javapackager.model.Platform;
10 | import io.github.fvarrui.javapackager.utils.FileUtils;
11 | import io.github.fvarrui.javapackager.utils.Logger;
12 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
13 |
14 | /**
15 | * Packager for GNU/Linux
16 | */
17 | public class LinuxPackager extends Packager {
18 |
19 | private File desktopFile;
20 | private File mimeXmlFile = null;
21 |
22 | public LinuxPackager() {
23 | super();
24 | installerGenerators.addAll(Context.getContext().getInstallerGenerators(Platform.linux));
25 | }
26 |
27 | public File getDesktopFile() {
28 | return desktopFile;
29 | }
30 |
31 | public File getMimeXmlFile() {
32 | return mimeXmlFile;
33 | }
34 |
35 | @Override
36 | public void doInit() throws Exception {
37 |
38 | // sets linux config default values
39 | this.linuxConfig.setDefaults(this);
40 |
41 | }
42 |
43 | @Override
44 | protected void doCreateAppStructure() throws Exception {
45 |
46 | // sets common folders
47 | this.executableDestinationFolder = appFolder;
48 | this.jarFileDestinationFolder = appFolder;
49 | this.jreDestinationFolder = new File(appFolder, jreDirectoryName);
50 | this.resourcesDestinationFolder = appFolder;
51 |
52 | }
53 |
54 | /**
55 | * Creates a GNU/Linux app folder with native executable
56 | */
57 | @Override
58 | public File doCreateApp() throws Exception {
59 |
60 | Logger.infoIndent("Creating GNU/Linux executable ...");
61 |
62 | // sets executable file
63 | this.executable = new File(appFolder, name);
64 |
65 | // process classpath
66 | if (classpath != null) {
67 | classpaths = Arrays.asList(classpath.split("[:;]"));
68 | if (!isUseResourcesAsWorkingDir()) {
69 | classpaths = classpaths.stream().map(cp -> new File(cp).isAbsolute() ? cp : "$SCRIPTPATH/" + cp).collect(Collectors.toList());
70 | }
71 | classpath = StringUtils.join(classpaths, ":");
72 | }
73 |
74 | // generates desktop file from velocity template
75 | desktopFile = new File(assetsFolder, name + ".desktop");
76 | VelocityUtils.render("linux/desktop.vtl", desktopFile, this);
77 | Logger.info("Rendering desktop file to " + desktopFile.getAbsolutePath());
78 |
79 | // generates mime.xml file from velocity template
80 | if (isThereFileAssociations()) {
81 | mimeXmlFile = new File(assetsFolder, name + ".xml");
82 | VelocityUtils.render("linux/mime.xml.vtl", mimeXmlFile, this);
83 | Logger.info("Rendering mime.xml file to " + mimeXmlFile.getAbsolutePath());
84 | }
85 |
86 | // generates startup.sh script to boot java app
87 | File startupFile = new File(assetsFolder, "startup.sh");
88 | VelocityUtils.render("linux/startup.sh.vtl", startupFile, this);
89 | Logger.info("Startup script generated in " + startupFile.getAbsolutePath());
90 |
91 | // concats linux startup.sh script + generated jar in executable (binary)
92 | if (getLinuxConfig().isWrapJar())
93 | FileUtils.concat(executable, startupFile, jarFile);
94 | else {
95 | FileUtils.copyFileToFile(startupFile, executable);
96 | FileUtils.copyFileToFolder(jarFile, appFolder);
97 | }
98 |
99 | // sets execution permissions
100 | executable.setExecutable(true, false);
101 |
102 | Logger.infoUnindent("GNU/Linux executable created in " + executable.getAbsolutePath() + "!");
103 |
104 | return appFolder;
105 | }
106 |
107 | }
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/PackagerFactory.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import org.apache.commons.lang3.SystemUtils;
4 |
5 | import io.github.fvarrui.javapackager.model.Platform;
6 |
7 | /**
8 | * Packager factory
9 | */
10 | public class PackagerFactory {
11 |
12 | public static Packager createPackager(Platform platform) throws Exception {
13 | if (platform == Platform.auto || platform == null) platform = Platform.getCurrentPlatform();
14 | Packager packager = null;
15 | switch (platform) {
16 | case mac:
17 | packager = new MacPackager(); break;
18 | case linux:
19 | packager = new LinuxPackager(); break;
20 | case windows:
21 | packager = new WindowsPackager(); break;
22 | default:
23 | throw new Exception("Unsupported operating system: " + SystemUtils.OS_NAME + " " + SystemUtils.OS_VERSION + " " + SystemUtils.OS_ARCH);
24 | }
25 | packager.platform(platform);
26 | return packager;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/packagers/WindowsPackager.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.packagers;
2 |
3 | import java.io.File;
4 | import java.util.Arrays;
5 | import java.util.stream.Collectors;
6 |
7 | import net.jsign.WindowsSigner;
8 | import org.apache.commons.lang3.StringUtils;
9 |
10 | import io.github.fvarrui.javapackager.model.Arch;
11 | import io.github.fvarrui.javapackager.model.Platform;
12 | import io.github.fvarrui.javapackager.utils.Logger;
13 | import io.github.fvarrui.javapackager.utils.VelocityUtils;
14 |
15 | /**
16 | * Packager for Windows
17 | */
18 | public class WindowsPackager extends Packager {
19 |
20 | private File manifestFile;
21 | private File msmFile;
22 |
23 | public File getManifestFile() {
24 | return manifestFile;
25 | }
26 |
27 | public File getMsmFile() {
28 | return msmFile;
29 | }
30 |
31 | public void setMsmFile(File msmFile) {
32 | this.msmFile = msmFile;
33 | }
34 |
35 | public WindowsPackager() {
36 | super();
37 | platform(Platform.windows);
38 | }
39 |
40 | @Override
41 | public void doInit() throws Exception {
42 |
43 | // sets default system architecture
44 | if (getArch() != Arch.x64 && getArch() != Arch.x86) {
45 | if (Platform.windows.isCurrentPlatform())
46 | arch(Arch.getDefault());
47 | else
48 | arch(Arch.x64);
49 | }
50 |
51 | // sets windows config default values
52 | this.winConfig.setDefaults(this);
53 |
54 | }
55 |
56 | @Override
57 | protected void doCreateAppStructure() throws Exception {
58 |
59 | // sets common folders
60 | this.executableDestinationFolder = appFolder;
61 | this.jarFileDestinationFolder = appFolder;
62 | this.jreDestinationFolder = new File(appFolder, jreDirectoryName);
63 | this.resourcesDestinationFolder = appFolder;
64 |
65 | }
66 |
67 | /**
68 | * Creates a Windows app file structure with native executable
69 | */
70 | @Override
71 | public File doCreateApp() throws Exception {
72 |
73 | Logger.infoIndent("Creating windows EXE ... with " + getWinConfig().getExeCreationTool());
74 |
75 | // generates manifest file to require administrator privileges from velocity template
76 | manifestFile = new File(assetsFolder, name + ".exe.manifest");
77 | VelocityUtils.render("windows/exe.manifest.vtl", manifestFile, this);
78 | Logger.info("Exe manifest file generated in " + manifestFile.getAbsolutePath() + "!");
79 |
80 | // sets executable file
81 | executable = new File(appFolder, name + ".exe");
82 |
83 | // process classpath
84 | if (classpath != null) {
85 | classpaths = Arrays.asList(classpath.split("[;:]"));
86 | if (!isUseResourcesAsWorkingDir()) {
87 | classpaths = classpaths.stream().map(cp -> new File(cp).isAbsolute() ? cp : "%EXEDIR%/" + cp).collect(Collectors.toList());
88 | }
89 | classpath = StringUtils.join(classpaths, ";");
90 | }
91 |
92 | // invokes Windows exe artifact generator (building tool dependant)
93 | executable = Context.getContext().createWindowsExe(this);
94 |
95 | // signs the executable
96 | WindowsSigner.sign(executable, getDisplayName(), getUrl(), getWinConfig().getSigning());
97 |
98 | Logger.infoUnindent("Windows EXE file created in " + executable + "!");
99 |
100 | return appFolder;
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/utils/CharsetUtil.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.utils;
2 |
3 | import java.nio.charset.Charset;
4 | import java.nio.charset.StandardCharsets;
5 |
6 | import org.apache.commons.lang3.SystemUtils;
7 |
8 | public class CharsetUtil {
9 |
10 | private static Charset commandLineCharset;
11 |
12 | public static Charset getCommandLineCharset(){
13 | if (commandLineCharset == null) {
14 | if (SystemUtils.IS_OS_WINDOWS) {
15 | commandLineCharset = chcp();
16 | } else {
17 | commandLineCharset = Charset.defaultCharset();
18 | }
19 | }
20 | return commandLineCharset;
21 | }
22 |
23 | private static Charset chcp() {
24 | try{
25 | String result = CommandUtils.run("cmd", "/k", "chcp");
26 | String code = StringUtils.find("\\d+", result);
27 | Logger.debug("'chcp' code found: " + code);
28 | switch (code){
29 | case "37":
30 | case "037": return Charset.forName("IBM037");
31 | case "936": return Charset.forName("gb2312");
32 | case "950": return Charset.forName("big5");
33 | case "1145": return Charset.forName("IBM01145");
34 | case "1200": return StandardCharsets.UTF_16;
35 | case "51936": return Charset.forName("EUC-CN");
36 | case "65001": return StandardCharsets.UTF_8;
37 | }
38 | } catch (Exception e){
39 | // do nothing
40 | }
41 | return Charset.defaultCharset();
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/io/github/fvarrui/javapackager/utils/CommandUtils.java:
--------------------------------------------------------------------------------
1 | package io.github.fvarrui.javapackager.utils;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.File;
5 | import java.io.IOException;
6 | import java.io.InputStreamReader;
7 | import java.util.List;
8 |
9 | import org.apache.commons.lang3.StringUtils;
10 | import org.codehaus.plexus.util.cli.CommandLineException;
11 |
12 | /**
13 | * Command utils
14 | */
15 | public class CommandUtils {
16 |
17 | public static String executeOnDirectory(File workingDirectory, String executable, Object... arguments) throws IOException, CommandLineException {
18 | ExecutionResult result = executeWithResult(workingDirectory, executable, arguments);
19 | if (result.getExitCode() != 0) {
20 | throw new CommandLineException("Command execution failed: " + executable + " " + StringUtils.join(arguments, " "));
21 | }
22 | return result.getOutput();
23 | }
24 |
25 | public static String execute(File executable, Object... arguments) throws IOException, CommandLineException {
26 | return execute(executable.getAbsolutePath(), arguments);
27 | }
28 |
29 | public static String execute(String executable, Object... arguments) throws IOException, CommandLineException {
30 | return executeOnDirectory(new File("."), executable, arguments);
31 | }
32 |
33 | public static String execute(String executable, List