diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 00000000..634955e2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,111 @@
+name: Bug report
+description: Report a bug to help us improve
+labels:
+ - bug
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to file a bug. Please fill in the details below.
+
+ - type: input
+ id: version
+ attributes:
+ label: JavaPackager version
+ description: Exact version used (e.g., 1.7.5). If built from source, include the commit.
+ placeholder: e.g., 1.7.5
+ validations:
+ required: true
+
+ - type: dropdown
+ id: os
+ attributes:
+ label: Operating system
+ options:
+ - Windows
+ - macOS
+ - Linux
+ - Other
+ validations:
+ required: true
+
+ - type: input
+ id: os_version
+ attributes:
+ label: OS version
+ placeholder: e.g., Windows 11 23H2, Ubuntu 22.04, macOS 14.5
+
+ - type: dropdown
+ id: build_tool
+ attributes:
+ label: Build tool
+ options:
+ - Gradle
+ - Maven
+ - Other / N/A
+ validations:
+ required: true
+
+ - type: input
+ id: jdk
+ attributes:
+ label: JDK version
+ placeholder: e.g., Temurin 21.0.3+9, Oracle JDK 17.0.10
+ validations:
+ required: true
+
+ - type: textarea
+ id: short_description
+ attributes:
+ label: Short description
+ description: What happens in one or two sentences?
+ placeholder: Clear and concise description of the problem.
+ validations:
+ required: true
+
+ - type: textarea
+ id: steps
+ attributes:
+ label: Steps to reproduce
+ description: Provide minimal, reproducible steps.
+ placeholder: |
+ 1. Step one
+ 2. Step two
+ 3. Observed result
+ render: text
+ validations:
+ required: true
+
+ - type: textarea
+ id: expected
+ attributes:
+ label: Expected behavior
+ placeholder: What did you expect to happen?
+ validations:
+ required: true
+
+ - type: textarea
+ id: actual
+ attributes:
+ label: Actual behavior
+ placeholder: What actually happens?
+ validations:
+ required: true
+
+ - type: textarea
+ id: logs
+ attributes:
+ label: Logs and output
+ description: Paste relevant output or attach files.
+ placeholder: Add logs, stack traces, console output, etc.
+ render: text
+
+ - type: checkboxes
+ id: checklist
+ attributes:
+ label: Checklist
+ options:
+ - label: I searched for existing related issues
+ required: true
+ - label: I can provide a minimal reproducible example if needed
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..dec06859
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Documentation
+ url: https://github.com/javapackager/JavaPackager/blob/master/README.md
+ about: Check the documentation before opening an issue.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 00000000..a19ed75b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,55 @@
+name: Feature request
+description: Suggest a new feature or improvement
+labels:
+ - enhancement
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for suggesting an improvement. Tell us the problem and your proposed solution.
+
+ - type: textarea
+ id: problem
+ attributes:
+ label: Problem to solve
+ description: What need or pain point motivates this feature?
+ placeholder: Describe the problem or use case.
+ validations:
+ required: true
+
+ - type: textarea
+ id: proposal
+ attributes:
+ label: Proposed solution
+ description: Explain how you would like it to work.
+ placeholder: Detail the proposed change and expected behavior.
+ validations:
+ required: true
+
+ - type: textarea
+ id: alternatives
+ attributes:
+ label: Alternatives considered
+ placeholder: What other options did you consider?
+
+ - type: textarea
+ id: impact
+ attributes:
+ label: Impact and scope
+ placeholder: Affected users, compatibility, risks, etc.
+
+ - type: input
+ id: version
+ attributes:
+ label: JavaPackager version (if applicable)
+ placeholder: e.g., 1.7.5
+
+ - type: checkboxes
+ id: checklist
+ attributes:
+ label: Checklist
+ options:
+ - label: I searched for existing similar issues
+ required: true
+ - label: I am willing to contribute a PR
+ required: false
diff --git a/.github/issue_template.md b/.github/issue_template.md
deleted file mode 100644
index c1254cc1..00000000
--- a/.github/issue_template.md
+++ /dev/null
@@ -1,42 +0,0 @@
-I'm submitting a…
-
-- [ ] bug report
-- [ ] feature request
-- [ ] other
-
-**Short description of the issue/suggestion:**
-
-
-
-**Steps to reproduce the issue/enhancement:**
-
-1. [First Step]
-2. [Second Step]
-3. [Other Steps...]
-
-**What is the expected behavior?**
-
-
-
-**What is the current behavior?**
-
-
-
-**Do you have outputs, screenshots, demos or samples which demonstrate the problem or enhancement?**
-
-
-
-**What is the motivation / use case for changing the behavior?**
-
-
-
-**Please tell us about your environment:**
-
-- JavaPackager version:
-- OS version:
-- JDK version:
-- Build tool:
- - [ ] Maven
- - [ ] Gradle
-
-**Other information** (e.g. related issues, suggestions how to fix, links for us to have context)
\ No newline at end of file
diff --git a/README.md b/README.md
index 231f50ca..b4ddf145 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,20 @@
# JavaPackager
-[](https://search.maven.org/artifact/io.github.fvarrui/javapackager)
+[](https://central.sonatype.com/search?smo=true&q=a%3Ajavapackager+g%3Aio.github.fvarrui)
[](https://www.gnu.org/licenses/gpl-3.0.html)
JavaPackager is a hybrid plugin for **Maven** and **Gradle** which provides an easy way to package Java applications in native Windows, MacOS or GNU/Linux executables, and generate installers for them.
-> SNAPSHOT version (available in `devel` branch) is not released to Maven Central, so you have to [install it manually](#how-to-build-and-install-the-plugin).
+> [!IMPORTANT]
+> See [JavaPackager changes and fixes](https://github.com/fvarrui/JavaPackager/releases).
-> :eyes: See [JavaPackager changes and fixes](https://github.com/fvarrui/JavaPackager/releases).
+## Project maintainers needed
+
+This project has been actively maintained for many years, but due to lack of time, I can no longer dedicate the attention it deserves. To keep it alive and evolving, I’m looking for contributors to help with its maintenance.
+
+:point_right: **[Join the discussion](https://github.com/fvarrui/JavaPackager/discussions/460)**
+
+Any help is welcome! Thank you for your support.
## History
@@ -60,6 +67,7 @@ Add the following `plugin` tag to your `pom.xml`:
```
+> [!tip]
> See [Maven plugin configuration samples](docs/maven/plugin-configuration-samples.md) to know more.
And execute the next command in project's root folder:
@@ -95,7 +103,7 @@ task packageMyApp(type: io.github.fvarrui.javapackager.gradle.PackageTask, depen
bundleJre = true|false
generateInstaller = true|false
administratorRequired = true|false
- platform = auto|linux|mac|windows
+ platform = "auto"|"linux"|"mac"|"windows"
additionalResources = [ file('file path'), file('folder path'), ... ]
linuxConfig {
...
@@ -110,7 +118,8 @@ task packageMyApp(type: io.github.fvarrui.javapackager.gradle.PackageTask, depen
}
```
-> See [Gradle plugin configuration samples](docs/gradle/plugin-configuration-samples.md) to know more.
+> [!TIP]
+> See [Gradle plugin configuration samples](docs/gradle/plugin-configuration-samples.md) to know more.
And execute the next command in project's root folder:
@@ -122,22 +131,23 @@ gradle packageMyApp
By default it will generate next artifacts in `${outputDirectory} ` folder:
-| Artifact | Description | Platform | Requires |
-| --------------------------------------- | ---------------------------------------------------------------- | --------- | --------------------------------------------------------------------------- |
-| `${name}` | Directory with native application and other assets. | All | |
-| `${name}-${version}-runnable.jar` | Runnable JAR file. | All | |
-| `${name}_${version}.AppImage` | AppImage package file. | GNU/Linux | [FUSE 2](https://github.com/AppImage/AppImageKit/wiki/FUSE) to run the app. |
-| `${name}_${version}.deb` | DEB package file. | All | |
-| `${name}_${version}.rpm` | RPM package file. | All | |
-| `${name}_${version}.exe` | Setup file. | Windows | [Inno Setup](http://www.jrsoftware.org/isinfo.php) |
-| `${name}_${version}.msi` | MSI installer file. | Windows | [WiX Toolset](https://wixtoolset.org/) |
-| `${name}_${version}.msm` | MSI merge module file. | Windows | [WiX Toolset](https://wixtoolset.org/) |
-| `${name}_${version}.dmg` | Disk image file (uses **hdiutil**). | MacOS | |
-| `${name}_${version}.pkg` | PKG installer file (uses **pkgbuild**). | MacOS | |
-| `${name}-${version}-${platform}.zip` | Zipball containing generated directory `${name}`. | All | |
-| `${name}-${version}-${platform}.tar.gz` | Compressed tarball containing generated directory `${name}`. | All | |
-| `assets` | Directory with all intermediate files generated by JavaPackager. | All | |
-
+| Artifact | Description | Platform | Requires |
+| --------------------------------------- | ---------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------ |
+| `${name}` | Directory with native application and other assets. | All | |
+| `${name}-${version}-runnable.jar` | Runnable JAR file. | All | |
+| `${name}_${version}.AppImage` | AppImage package file. | GNU/Linux | [FUSE 2](https://github.com/AppImage/AppImageKit/wiki/FUSE) to run the app. |
+| `${name}_${version}.deb` | DEB package file. | All | |
+| `${name}_${version}.rpm` | RPM package file. | All | |
+| `${name}_${version}.exe` | Setup file. | Windows | [Inno Setup](http://www.jrsoftware.org/isinfo.php)Â (`iscc`Â command must be in PATH variable) |
+| `${name}_${version}.msi` | MSI installer file. | Windows | [WiX Toolset](https://wixtoolset.org/)Â (`candle`Â and `light` commands must be in PATH variable) |
+| `${name}_${version}.msm` | MSI merge module file. | Windows | [WiX Toolset](https://wixtoolset.org/)Â (Â `candle`Â and `light` commands must be in PATH variable) |
+| `${name}_${version}.dmg` | Disk image file (uses **hdiutil**). | MacOS | |
+| `${name}_${version}.pkg` | PKG installer file (uses **pkgbuild**). | MacOS | |
+| `${name}-${version}-${platform}.zip` | Zipball containing generated directory `${name}`. | All | |
+| `${name}-${version}-${platform}.tar.gz` | Compressed tarball containing generated directory `${name}`. | All | |
+| `assets` | Directory with all intermediate files generated by JavaPackager. | All | |
+
+> [!TIP]
> **Inno Setup** and **WiX Toolset** installation [guide](docs/windows-tools-guide.md).
### Plugin configuration properties
@@ -147,6 +157,7 @@ By default it will generate next artifacts in `${outputDirectory} ` folder:
| `additionalModulePaths` | :x: | `[]` | Additional module paths for `jdeps`. |
| `additionalModules` | :x: | `[]` | Additional modules to the ones identified by `jdeps` or the specified with `modules` property. |
| `additionalResources` | :x: | `[]` | Additional files and folders to include in the bundled app. |
+| `arch` | :x: | `${os.arch}` | The dependency of some ArtifactGenerator objects in the process of making packages, such as GenerateDeb |
| `administratorRequired` | :x: | `false` | App will run as administrator (with elevated privileges). |
| `assetsDir` | :x: | `${basedir}/assets` or `${projectdir}/assets` | Assets location (icons and custom Velocity templates). |
| `bundleJre` | :x: | `false` | Embeds a customized JRE with the app. |
@@ -184,6 +195,7 @@ By default it will generate next artifacts in `${outputDirectory} ` folder:
| `version` | :x: | `${project.version}` | App version. |
| `vmArgs` | :x: | `[]` | VM arguments. |
+> [!IMPORTANT]
> Some default values depends on the used building tool.
**Platform specific properties**
@@ -194,7 +206,8 @@ By default it will generate next artifacts in `${outputDirectory} ` folder:
| `macConfig` | :x: | [MacOS specific properties](docs/macosx-specific-properties.md). |
| `winConfig` | :x: | [Windows specific properties](docs/windows-specific-properties.md). |
-> :warning: Be careful when using the `platform` property if your project uses platform dependent libraries, so the libraries of the current platform will be copied, not those required for the target platform. You can solve this problem using `classifiers`.
+> [!WARNING]
+> Be careful when using the `platform` property if your project uses platform dependent libraries, so the libraries of the current platform will be copied, not those required for the target platform. You can solve this problem using `classifiers`.
### Plugin assets
@@ -221,7 +234,8 @@ ${assetsDir}/
└── ${name}.ico # on Windows it has to be a ICO file
```
-> :warning: If icon is not specified , it will use an [icon by default](https://raw.githubusercontent.com/fvarrui/JavaPackager/master/src/main/resources/linux/default-icon.png) for all platforms.
+> [!WARNING]
+> If icon is not specified , it will use an [icon by default](https://raw.githubusercontent.com/fvarrui/JavaPackager/master/src/main/resources/linux/default-icon.png) for all platforms.
#### Templates
@@ -260,7 +274,7 @@ You can use [default templates](https://github.com/fvarrui/JavaPackager/tree/mas
### Additional JVM options at runtime
-When you build your app, all configuration details are hardcoded into the executable and cannot be changed without recreating it or hacking with a resource editor. JavaPackager introduces a feature that allows to pass additional JVM options at runtime from an `.l4j.ini` file (like [Launch4j](http://launch4j.sourceforge.net/docs.html) does, but available for all platforms in the same way). So, you can specify these options in the packager's configuration (packaging time), in INI file (runtime) or in both.
+When you build your app, all configuration details are hardcoded into the executable and cannot be changed without recreating or hacking it with a resource editor. JavaPackager introduces a feature that allows to pass additional JVM options at runtime from an `.l4j.ini` file (like [Launch4j](http://launch4j.sourceforge.net/docs.html) does, but available for all platforms in the same way). So, you can specify these options in the packager's configuration (packaging time), in INI file (runtime) or in both.
The INI file's name must correspond to `${name}.l4j.ini` and it has to be located next to the executable on Windows and GNU/Linux, and in `Resources` folder on MacOS.
@@ -273,7 +287,8 @@ The options should be separated with spaces or new lines:
-Xms16m
```
-> An VM argument per line.
+> [!IMPORTANT]
+> An VM argument per line.
And then bundle this file with your app:
@@ -283,11 +298,89 @@ And then bundle this file with your app:
```
+> [!NOTE]
> Last property copies `${name}.l4j.ini` file next to the EXE/binary on Windows/Linux, and in `Resources` folder on MacOS.
-## How to build and install the plugin
+## How to use SNAPSHOT versions
+
+[Here](https://oss.sonatype.org/content/repositories/snapshots/io/github/fvarrui/javapackager/) you can find the uploaded JavaPackager SNAPSHOT versions.
+
+### Maven
+
+Add the plugin repository to your `pom.xml`:
+
+```xml
+
+
+ nexus
+ nexus-snapshot-repository
+ https://oss.sonatype.org/content/repositories/snapshots
+
+ true
+ always
+
+
+ false
+
+
+
+```
+
+And then you can use the latest SNAPSHOT version:
+
+```xml
+
+ io.github.fvarrui
+ javapackager
+ {javapackager.version}-SNAPSHOT
+ [...]
+
+```
+
+Or a specific SNAPSHOT version (specifying its timestamp and index):
+
+```xml
+
+ io.github.fvarrui
+ javapackager
+ {javapackager.version}-{timestamp}-{index}
+ [...]
+
+```
+
+> SNAPSHOT version example: `1.7.2-20230505.095442-5`.
+
+### Gradle
-Useful to try SNAPSHOT versions.
+Add the plugin repository to your `build.gradle` and use the latest SNAPSHOT version:
+
+```groovy
+buildscript {
+ repositories {
+ maven {
+ url "https://oss.sonatype.org/content/repositories/snapshots"
+ }
+ }
+ dependencies {
+ classpath 'io.github.fvarrui:javapackager:{javapackager.version}-SNAPSHOT'
+ }
+}
+```
+
+Or set a specific SNAPSHOT version specifying its timestamp and index:
+
+```groovy
+buildscript {
+ [...]
+ dependencies {
+ classpath 'io.github.fvarrui:javapackager:{javapackager.version}-{timestamp}-{index}'
+ }
+}
+```
+
+> SNAPSHOT version example: `1.7.2-20230505.095442-5`.
+
+## How to build and install the plugin in your local repo
Execute next commands in BASH (GNU/Linux or macOS) or CMD (Windows):
@@ -304,16 +397,13 @@ cd JavaPackager
./gradlew publishToMavenLocal
```
+> [!IMPORTANT]
+> It is recommended to build the plugin with Java 19.
+
## How to release the plugin to Maven Central
Run next command (ommit `./` on Windows):
```bash
-./gradlew -Prelease uploadArchives closeAndReleaseRepository
+./gradlew publish closeAndReleaseRepository
```
-
-> Related [guide](https://nemerosa.ghost.io/2015/07/01/publishing-to-the-maven-central-using-gradle/).
-
-## Future features
-
-Check the [TO-DO list](https://github.com/fvarrui/JavaPackager/projects/1#column-7704117) to know the features we plan to add to JavaPackager.
diff --git a/build.gradle b/build.gradle
index 6ea104dd..454b9f65 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,12 +1,12 @@
plugins {
id 'java'
- id 'maven'
id 'maven-publish'
id 'java-gradle-plugin'
- id 'com.gradle.plugin-publish' version '0.12.0'
+ id 'com.gradle.plugin-publish' version '1.1.0'
id 'io.codearte.nexus-staging' version '0.21.2'
id 'eclipse'
id 'de.undercouch.download' version '5.0.4'
+ id 'signing'
}
repositories {
@@ -18,22 +18,16 @@ repositories {
}
gradlePlugin {
- plugins {
- javaPackagerPlugin {
- id = 'io.github.fvarrui.javapackager.plugin'
- implementationClass = 'io.github.fvarrui.javapackager.gradle.PackagePlugin'
- }
- }
-}
-
-pluginBundle {
website = 'http://github.com/fvarrui/JavaPackager'
vcsUrl = 'http://github.com/fvarrui/JavaPackager.git'
description = 'Packages Java applications as native Windows, MacOS or GNU/Linux executables and creates installers for them'
- tags = ['java', 'packager', 'gradle-plugin', 'maven-plugin', 'native', 'installer', 'debian-packages', 'rpm-packages', 'dmg', 'maven', 'gradle', 'distribution', 'javapackager', 'linux-executables', 'deb', 'rpm', 'native-windows', 'java-applications', 'pkg', 'msi']
+
plugins {
- javaPackagerPlugin {
+ create("javaPackagerPlugin") {
+ id = 'io.github.fvarrui.javapackager.plugin'
displayName = 'JavaPackager'
+ implementationClass = 'io.github.fvarrui.javapackager.gradle.PackagePlugin'
+ tags.set(['java', 'packager', 'gradle-plugin', 'maven-plugin', 'native', 'installer', 'debian-packages', 'rpm-packages', 'dmg', 'maven', 'gradle', 'distribution', 'javapackager', 'linux-executables', 'deb', 'rpm', 'native-windows', 'java-applications', 'pkg', 'msi'])
}
}
}
@@ -44,19 +38,19 @@ configurations {
dependencies {
implementation 'org.apache.maven:maven-plugin-api:3.6.0'
- implementation 'org.codehaus.plexus:plexus-utils:3.1.1'
+ implementation 'org.codehaus.plexus:plexus-utils:3.5.1'
implementation 'org.twdata.maven:mojo-executor:2.3.0'
- implementation 'commons-io:commons-io:2.11.0'
+ implementation 'commons-io:commons-io:2.16.1'
implementation 'org.apache.commons:commons-lang3:3.9'
- implementation 'org.apache.commons:commons-collections4:4.1'
+ implementation 'org.apache.commons:commons-collections4:4.3'
implementation 'org.apache.commons:commons-compress:1.21'
- implementation 'org.apache.velocity:velocity-engine-core:2.0'
+ implementation 'org.apache.velocity:velocity-engine-core:2.3'
implementation 'org.vafer:jdeb:1.9'
- implementation 'net.jsign:jsign-core:3.1'
+ implementation 'net.jsign:jsign-core:6.0'
implementation 'org.redline-rpm:redline:1.2.10'
- implementation 'io.github.fvarrui:launch4j:2.5.2'
+ implementation 'edu.sc.seis.launch4j:launch4j:3.0.5'
- testImplementation 'junit:junit:4.12'
+ testImplementation 'junit:junit:4.13.1'
compileOnly 'org.apache.maven.plugin-tools:maven-plugin-annotations:3.6.0'
@@ -70,7 +64,7 @@ dependencies {
}
group = 'io.github.fvarrui'
-version = '1.7.0'
+version = '1.7.6'
description = 'Hybrid Maven/Gradle plugin to package Java applications as native Windows, Mac OS X or GNU/Linux executables and create installers for them'
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -78,180 +72,152 @@ targetCompatibility = JavaVersion.VERSION_1_8
compileJava.options.encoding = 'UTF-8'
-publishing {
- publications {
- mavenJava(MavenPublication) {
- from(components.java)
- }
- }
-}
+// suppress javadoc warnings
+javadoc.options.addStringOption('Xdoclint:none', '-quiet')
java {
withSourcesJar()
- // and/or analogously use "withJavadocJar()" to get a "javadocJar" task
+ withJavadocJar()
}
-install.repositories.mavenInstaller.pom.with {
- groupId = project.group
- artifactId = project.name
- version = project.version
- description = project.description
- packaging = 'maven-plugin'
-}
+// OSSRH publication
+publishing {
+ repositories {
+ maven {
+ def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
+ def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots"
+ name = "OSSRH"
+ url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
+ credentials {
+ username = project.findProperty("ossrhUsername") ?: ''
+ password = project.findProperty("ossrhPassword") ?: ''
+ }
+ }
+ }
+ publications {
+ pluginMaven(MavenPublication) {
+ def directory = buildDir.canonicalPath
+ def outputDirectory = compileJava.destinationDirectory.asFile.get().canonicalPath
+ pom.withXml {
+ asNode().appendNode('build')
+ .with {
+ appendNode('directory', directory)
+ appendNode('outputDirectory', outputDirectory)
+ }
+ asNode().appendNode('repositories').appendNode('repository')
+ .with {
+ appendNode('id', 'gradle')
+ appendNode('name', 'Gradle Plugin Portal')
+ appendNode('url', 'https://plugins.gradle.org/m2/')
+ }
+ }
+ pom {
+ name = project.name
+ groupId = project.group
+ artifactId = project.name
+ packaging = 'maven-plugin'
+ }
+ }
+ }
-build.dependsOn ':winrun4j-launcher:build'
+ afterEvaluate {
+ publications {
+ withType(MavenPublication) {
+ // customize all publications here
+ pom {
+ version = project.version
+ description = project.description
+ url = 'https://github.com/fvarrui/JavaPackager'
+ scm {
+ connection = 'scm:git:git://github.com/fvarrui/JavaPackager.git'
+ developerConnection = 'scm:git:git@github.com:fvarrui/fvarrui.git'
+ url = 'https://github.com/fvarrui/JavaPackager'
+ }
+ licenses {
+ license {
+ name = 'GPL-v3.0'
+ url = 'http://www.gnu.org/licenses/gpl-3.0.txt'
+ distribution = 'repo'
+ }
+ }
+ developers {
+ developer {
+ id = 'fvarrui'
+ name = 'Francisco Vargas Ruiz'
+ url = 'https://github.com/fvarrui'
+ }
+ }
+ }
+ }
+ }
+ }
+}
// runs the plugin description generator
-task generatePluginDescriptor(type: JavaExec, dependsOn: compileJava) {
-
- def pomFile = file("$buildDir/pom.xml")
- def pluginDescriptorFile = new File(project.compileJava.destinationDir, 'META-INF/maven/plugin.xml')
- def directory = buildDir.canonicalPath
- def outputDirectory = compileJava.destinationDir.canonicalPath
+tasks.register('generatePluginDescriptor', JavaExec) {
+ dependsOn compileJava
+ def pluginDescriptorFile = new File(project.compileJava.destinationDirectory.asFile.get(), 'META-INF/maven/plugin.xml')
// FIXME: this does not seem to be working
inputs.files project.compileJava.outputs.files
outputs.file pluginDescriptorFile
classpath = configurations.mavenEmbedder
- main = 'org.apache.maven.cli.MavenCli'
+ mainClass = 'org.apache.maven.cli.MavenCli'
systemProperties['maven.multiModuleProjectDirectory'] = projectDir
args = [
'--errors',
'--batch-mode',
- '--file', "${buildDir}/pom.xml",
- 'org.apache.maven.plugins:maven-plugin-plugin:3.6.0:descriptor',
+ '--file', generatePomFileForPluginMavenPublication.destination,
+ 'org.apache.maven.plugins:maven-plugin-plugin:3.9.0:descriptor',
'-Dproject.build.sourceEncoding=' + compileJava.options.encoding
]
-
- doFirst {
- install.repositories
- .mavenInstaller
- .pom
- .withXml {
- asNode().appendNode('repositories').appendNode('repository')
- .with {
- appendNode('id', 'gradle')
- appendNode('name', 'Gradle Plugin Portal')
- appendNode('url', 'https://plugins.gradle.org/m2/')
- }
- asNode().appendNode('build')
- .with {
- appendNode('directory', directory)
- appendNode('outputDirectory', outputDirectory)
- }
- }
- .writeTo(pomFile)
-
- assert pomFile.file, "${pomFile.canonicalPath}: was not generated"
- logger.info("POM is generated in ${pomFile.canonicalPath}")
- }
-
doLast {
assert pluginDescriptorFile.file, "${pluginDescriptorFile.canonicalPath}: was not generated"
logger.info("Plugin descriptor is generated in ${pluginDescriptorFile.canonicalPath}")
}
}
+generatePluginDescriptor.dependsOn(generatePomFileForPluginMavenPublication)
-project.jar.dependsOn(generatePluginDescriptor)
+project.classes.dependsOn(generatePluginDescriptor)
+project.validatePlugins.dependsOn(generatePluginDescriptor)
publishToMavenLocal.dependsOn(build)
-
-if (project.hasProperty('release')) {
- apply plugin: 'signing'
- apply plugin: 'maven'
-
- task deployingJavadocJar(type: Jar) {
- classifier = 'javadoc'
- from javadoc
- }
-
- task deployingSourcesJar(type: Jar) {
- classifier = 'sources'
- from sourceSets.main.allSource
- }
-
- artifacts {
- archives deployingJavadocJar, deployingSourcesJar
+// Signature of publication
+signing {
+ setRequired {
+ // signing is only required if the artifacts are to be published
+ gradle.taskGraph.allTasks.any { it instanceof PublishToMavenRepository }
}
-
- // Signature of artifacts
- signing {
- sign configurations.archives
- }
-
- // OSSRH publication
- uploadArchives {
- repositories {
- mavenDeployer {
- // POM signature
- beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
- // Target repository
- repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
- authentication(userName: ossrhUser, password: ossrhPassword)
- }
- pom.project {
- name project.name
- description project.description
- packaging = 'maven-plugin'
- url 'https://github.com/fvarrui/JavaPackager'
-
- scm {
- connection 'scm:git:git://github.com/fvarrui/JavaPackager.git'
- developerConnection 'scm:git:git@github.com:fvarrui/fvarrui.git'
- url 'https://github.com/fvarrui/JavaPackager'
- }
-
- licenses {
- license {
- name 'GPL-v3.0'
- url 'http://www.gnu.org/licenses/gpl-3.0.txt'
- distribution 'repo'
- }
- }
-
- developers {
- developer {
- id = 'fvarrui'
- name = 'Francisco Vargas Ruiz'
- url = 'https://github.com/fvarrui'
- }
- }
- }
- }
- }
- }
-
+ sign publishing.publications.pluginMaven
}
nexusStaging {
- username = project.findProperty('ossrhUser') ?: ''
+ username = project.findProperty('ossrhUsername') ?: ''
password = project.findProperty('ossrhPassword') ?: ''
}
-
-task updateUniversalJavaApplicationStub(type : Download) {
- def version = '20220410.162252'
+tasks.register('updateUniversalJavaApplicationStub', Download) {
+ def version = '20230601.235708'
group 'Update assets'
- description 'Downloads compiled and scripted versions of universalJavaApplicationStub to src/main/resources/mac overriding the existing ones.'
+ description 'Downloads compiled and scripted versions of universalJavaApplicationStub to src/main/resources/mac overriding the existing ones.'
src([
- "https://github.com/fvarrui/universalJavaApplicationStub/releases/download/${version}/universalJavaApplicationStub.sh",
- "https://github.com/fvarrui/universalJavaApplicationStub/releases/download/${version}/universalJavaApplicationStub.x86_64",
- "https://github.com/fvarrui/universalJavaApplicationStub/releases/download/${version}/universalJavaApplicationStub.arm64",
- "https://github.com/fvarrui/universalJavaApplicationStub/releases/download/${version}/universalJavaApplicationStub"
+ "https://github.com/fvarrui/universalJavaApplicationStub/releases/download/${version}/universalJavaApplicationStub.sh",
+ "https://github.com/fvarrui/universalJavaApplicationStub/releases/download/${version}/universalJavaApplicationStub.x86_64",
+ "https://github.com/fvarrui/universalJavaApplicationStub/releases/download/${version}/universalJavaApplicationStub.arm64",
+ "https://github.com/fvarrui/universalJavaApplicationStub/releases/download/${version}/universalJavaApplicationStub"
])
dest file('src/main/resources/mac')
- overwrite true
+ overwrite true
}
-task updateWhyJavaLauncher(type : Download) {
+tasks.register('updateWhyJavaLauncher', Download) {
def version = '1.1.2'
group 'Update assets'
- description 'Downloads JavaLauncher.exe to src/main/resources/windows and overwrites the existing one.'
+ description 'Downloads JavaLauncher.exe to src/main/resources/windows and overwrites the existing one.'
src([
- "https://github.com/AstroImageJ/Why/releases/download/${version}/JavaLauncher.exe"
+ "https://github.com/AstroImageJ/Why/releases/download/${version}/JavaLauncher.exe"
])
dest file('src/main/resources/windows')
- overwrite true
+ overwrite true
}
-
diff --git a/docs/macosx-specific-properties.md b/docs/macosx-specific-properties.md
index 57a4c291..d104c2e4 100644
--- a/docs/macosx-specific-properties.md
+++ b/docs/macosx-specific-properties.md
@@ -16,6 +16,8 @@
path/to/entitlements.plist
true|false
true|false
+ true|false
+ xcrun_notarytool_profile_name
path/to/png
@@ -62,11 +64,13 @@
## Signing properties
| Property | Mandatory | Default value | Description |
-| ------------------ | --------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
+|--------------------| --------- |---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| `developerId` | :x: | | Signing identity. |
| `entitlements` | :x: | | Path to [entitlements](https://developer.apple.com/documentation/bundleresources/entitlements) file. |
| `codesignApp` | :x: | `true` | If it is set to `false`, generated app will not be codesigned. |
| `hardenedCodesign` | :x: | `true` | If it is set to `true`, enable [hardened runtime](https://developer.apple.com/documentation/security/hardened_runtime) if MacOS version >= 10.13.6. |
+| `notarizeApp` | :x: | `false` | If it is set to `true`, generated app will be submitted to apple for notarization and the ticket will be stapled. |
+| `keyChainProfile` | :x: | | Profile name originally provided to `xcrun notarytool store-credentials`. Must be set if `notarizeApp` is `true`.
| `macStartup` | :x: | `SCRIPT` | App startup type, using a `SCRIPT` or a binary (compiled version of the script:Â `UNIVERSAL`, `X86_64`Â or `ARM64`). |
## DMG generation properties
diff --git a/docs/windows-specific-properties.md b/docs/windows-specific-properties.md
index 9aac4ac5..aefe27aa 100644
--- a/docs/windows-specific-properties.md
+++ b/docs/windows-specific-properties.md
@@ -10,7 +10,7 @@
true|false
- gui
+ gui|console
true|false
${organizationName}
1.0.0.0
@@ -21,6 +21,7 @@
${organizationName}
${name}
${name}
+ ${name}
${name}.exe
@@ -55,10 +56,10 @@
- root:path/to/my/key
- name
- type
- data
+ root:path/to/my/key
+ name
+ type
+ data
[...]
@@ -103,6 +104,7 @@
| ------------------------- | --------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `setupMode` | :x: | `installForAllUsers` | Setup installation mode: require administrative privileges or not. [*](#setupmode) |
| `setupLanguages` | :x: | `compiler:Default.islcompiler:Languages\Spanish.isl` | Map with setup languages. |
+| `shortcutName` | :x: | `${name}` | Sets the name of the user optional shortcut created on the desktop |
| `disableDirPage` | :x: | `true` | If this is set to `true`, Setup will not show the **Select Destination Location** wizard page. |
| `disableProgramGroupPage` | :x: | `true` | If this is set to `true`, Setup will not show the **Select Start Menu Folder** wizard page. |
| `disableFinishedPage` | :x: | `true` | If this is set to `true`, Setup will not show the **Setup Completed** wizard page. |
diff --git a/docs/windows-tools-guide.md b/docs/windows-tools-guide.md
index 2a4fa382..e41b8391 100644
--- a/docs/windows-tools-guide.md
+++ b/docs/windows-tools-guide.md
@@ -1,6 +1,8 @@
# Windows tools installation guide
-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 a MSI file.
+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.
+
+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.
## Using Chocolatey
You can install both tools in a simple way using [Chocolatey](https://chocolatey.org/) package manager:
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e64ee76b..e1bef7e8 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=7faa7198769f872826c8ef4f1450f839ec27f0b4d5d1e51bade63667cbccd205
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
\ No newline at end of file
+zipStorePath=wrapper/dists
diff --git a/settings.gradle b/settings.gradle
index 03800abd..b4ae1d88 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1 @@
-rootProject.name = 'javapackager'
-include 'winrun4j-launcher'
\ No newline at end of file
+rootProject.name = 'javapackager'
\ No newline at end of file
diff --git a/src/main/java/io/github/fvarrui/javapackager/gradle/CopyDependencies.java b/src/main/java/io/github/fvarrui/javapackager/gradle/CopyDependencies.java
index a4f0e250..f6881ad0 100644
--- a/src/main/java/io/github/fvarrui/javapackager/gradle/CopyDependencies.java
+++ b/src/main/java/io/github/fvarrui/javapackager/gradle/CopyDependencies.java
@@ -35,7 +35,8 @@ protected File doApply(Packager packager) {
if (copyLibsTask == null) {
copyLibsTask = project.getTasks().create("copyLibs", Copy.class);
}
- copyLibsTask.from(project.getConfigurations().getByName("default"));
+ copyLibsTask.setDuplicatesStrategy(Context.getGradleContext().getDuplicatesStrategy());
+ copyLibsTask.from(project.getConfigurations().getByName("runtimeClasspath"));
copyLibsTask.into(project.file(libsFolder));
copyLibsTask.getActions().forEach(action -> action.execute(copyLibsTask));
diff --git a/src/main/java/io/github/fvarrui/javapackager/gradle/CreateWindowsExeLaunch4j.java b/src/main/java/io/github/fvarrui/javapackager/gradle/CreateWindowsExeLaunch4j.java
index b2529a8b..0af1f1a5 100644
--- a/src/main/java/io/github/fvarrui/javapackager/gradle/CreateWindowsExeLaunch4j.java
+++ b/src/main/java/io/github/fvarrui/javapackager/gradle/CreateWindowsExeLaunch4j.java
@@ -4,6 +4,7 @@
import java.util.HashSet;
import java.util.List;
+import net.jsign.WindowsSigner;
import org.apache.commons.lang3.StringUtils;
import edu.sc.seis.launch4j.tasks.Launch4jLibraryTask;
@@ -49,36 +50,35 @@ protected File doApply(WindowsPackager packager) throws Exception {
}
Launch4jLibraryTask l4jTask = Context.getGradleContext().getLibraryTask();
+ l4jTask.getDuplicatesStrategy().set(Context.getGradleContext().getDuplicatesStrategy());
l4jTask.getOutputs().upToDateWhen(task -> false);
- l4jTask.setHeaderType(winConfig.getHeaderType().toString());
- l4jTask.setJar(jarPath);
- l4jTask.setDontWrapJar(!winConfig.isWrapJar());
- l4jTask.setOutfile(getGenericExe().getName());
- l4jTask.setIcon(getGenericIcon().getAbsolutePath());
- l4jTask.setManifest(getGenericManifest().getAbsolutePath());
- l4jTask.setMainClassName(mainClass);
- l4jTask.setClasspath(new HashSet<>(packager.getClasspaths()));
- l4jTask.setChdir(useResourcesAsWorkingDir ? "." : "");
+ l4jTask.getHeaderType().set(winConfig.getHeaderType().toString());
+ l4jTask.getJarFiles().set(Context.getGradleContext().getProject().files(jarPath));
+ l4jTask.getDontWrapJar().set(!winConfig.isWrapJar());
+ l4jTask.getOutfile().set(getGenericExe().getName());
+ l4jTask.getIcon().set(getGenericIcon().getAbsolutePath());
+ l4jTask.getManifest().set(getGenericManifest().getAbsolutePath());
+ l4jTask.getMainClassName().set(mainClass);
+ l4jTask.getClasspath().set(new HashSet<>(packager.getClasspaths()));
+ l4jTask.getChdir().set(useResourcesAsWorkingDir ? "." : "");
if (bundleJre) {
- l4jTask.setBundledJrePath(jreDirectoryName);
+ l4jTask.getBundledJrePath().set(jreDirectoryName);
}
if (!StringUtils.isBlank(jreMinVersion)) {
- l4jTask.setJreMinVersion(jreMinVersion);
+ l4jTask.getJreMinVersion().set(jreMinVersion);
}
l4jTask.getJvmOptions().addAll(vmArgs);
- l4jTask.setVersion(winConfig.getProductVersion());
- l4jTask.setTextVersion(winConfig.getTxtProductVersion());
- l4jTask.setCopyright(winConfig.getCopyright());
- l4jTask.setCompanyName(winConfig.getCompanyName());
- l4jTask.setFileDescription(winConfig.getFileDescription());
- l4jTask.setProductName(winConfig.getProductName());
- l4jTask.setInternalName(winConfig.getInternalName());
- l4jTask.setTrademarks(winConfig.getTrademarks());
- l4jTask.setLanguage(winConfig.getLanguage());
+ l4jTask.getVersion().set(winConfig.getProductVersion());
+ l4jTask.getTextVersion().set(winConfig.getTxtProductVersion());
+ l4jTask.getCopyright().set(winConfig.getCopyright());
+ l4jTask.getCompanyName().set(winConfig.getCompanyName());
+ l4jTask.getFileDescription().set(winConfig.getFileDescription());
+ l4jTask.getProductName().set(winConfig.getProductName());
+ l4jTask.getInternalName().set(winConfig.getInternalName());
+ l4jTask.getTrademarks().set(winConfig.getTrademarks());
+ l4jTask.getLanguage().set(winConfig.getLanguage());
l4jTask.getActions().forEach(action -> action.execute(l4jTask));
- sign(getGenericExe(), packager);
-
FileUtils.copyFileToFile(getGenericExe(), executable);
return createBootstrapScript(packager);
diff --git a/src/main/java/io/github/fvarrui/javapackager/gradle/DefaultPackageTask.java b/src/main/java/io/github/fvarrui/javapackager/gradle/DefaultPackageTask.java
deleted file mode 100644
index 791a23be..00000000
--- a/src/main/java/io/github/fvarrui/javapackager/gradle/DefaultPackageTask.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package io.github.fvarrui.javapackager.gradle;
-
-import static io.github.fvarrui.javapackager.utils.ObjectUtils.defaultIfNull;
-
-import io.github.fvarrui.javapackager.packagers.Packager;
-import io.github.fvarrui.javapackager.packagers.PackagerFactory;
-
-/**
- * Default packaging task for Gradle
- */
-public class DefaultPackageTask extends AbstractPackageTask {
-
- @Override
- protected Packager createPackager() throws Exception {
-
- PackagePluginExtension extension = getProject().getExtensions().findByType(PackagePluginExtension.class);
-
- return
- (Packager) PackagerFactory
- .createPackager(extension.getPlatform())
- .additionalModules(extension.getAdditionalModules())
- .additionalModulePaths(extension.getAdditionalModulePaths())
- .additionalResources(extension.getAdditionalResources())
- .administratorRequired(extension.getAdministratorRequired())
- .assetsDir(extension.getAssetsDir())
- .bundleJre(extension.getBundleJre())
- .classpath(extension.getClasspath())
- .copyDependencies(extension.getCopyDependencies())
- .createTarball(extension.getCreateTarball())
- .createZipball(extension.getCreateZipball())
- .customizedJre(extension.getCustomizedJre())
- .description(extension.getDescription())
- .displayName(extension.getDisplayName())
- .envPath(extension.getEnvPath())
- .extra(extension.getExtra())
- .fileAssociations(extension.getFileAssociations())
- .forceInstaller(extension.isForceInstaller())
- .generateInstaller(extension.getGenerateInstaller())
- .jdkPath(extension.getJdkPath())
- .jreDirectoryName(extension.getJreDirectoryName())
- .jreMinVersion(extension.getJreMinVersion())
- .jrePath(extension.getJrePath())
- .licenseFile(extension.getLicenseFile())
- .linuxConfig(extension.getLinuxConfig())
- .macConfig(extension.getMacConfig())
- .mainClass(extension.getMainClass())
- .manifest(extension.getManifest())
- .modules(extension.getModules())
- .name(extension.getName())
- .organizationEmail(extension.getOrganizationEmail())
- .organizationName(extension.getOrganizationName())
- .organizationUrl(extension.getOrganizationUrl())
- .outputDirectory(extension.getOutputDirectory())
- .packagingJdk(extension.getPackagingJdk())
- .runnableJar(extension.getRunnableJar())
- .scripts(extension.getScripts())
- .useResourcesAsWorkingDir(extension.isUseResourcesAsWorkingDir())
- .url(extension.getUrl())
- .version(defaultIfNull(extension.getVersion(), getProject().getVersion().toString()))
- .vmArgs(extension.getVmArgs())
- .winConfig(extension.getWinConfig());
-
- }
-
-}
diff --git a/src/main/java/io/github/fvarrui/javapackager/gradle/GradleContext.java b/src/main/java/io/github/fvarrui/javapackager/gradle/GradleContext.java
index b83eea0e..b2e1f206 100644
--- a/src/main/java/io/github/fvarrui/javapackager/gradle/GradleContext.java
+++ b/src/main/java/io/github/fvarrui/javapackager/gradle/GradleContext.java
@@ -4,6 +4,7 @@
import io.github.fvarrui.javapackager.packagers.*;
import org.gradle.api.Project;
+import org.gradle.api.file.DuplicatesStrategy;
import org.gradle.api.internal.provider.Providers;
import org.gradle.api.logging.Logger;
import org.gradle.api.plugins.JavaPluginExtension;
@@ -20,8 +21,8 @@
public class GradleContext extends Context {
private Project project;
-
private Launch4jLibraryTask libraryTask;
+ private DuplicatesStrategy duplicatesStrategy;
public GradleContext(Project project) {
super();
@@ -80,6 +81,14 @@ public void setLibraryTask(Launch4jLibraryTask libraryTask) {
this.libraryTask = libraryTask;
}
+ public DuplicatesStrategy getDuplicatesStrategy() {
+ return duplicatesStrategy;
+ }
+
+ public void setDuplicatesStrategy(DuplicatesStrategy duplicatesStrategy) {
+ this.duplicatesStrategy = duplicatesStrategy;
+ }
+
/**
* Returns project's default toolchain
*
@@ -122,7 +131,5 @@ public File createWindowsExe(WindowsPackager packager) throws Exception {
}
return null;
}
-
-
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePlugin.java b/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePlugin.java
index 844d2ca0..b817168b 100644
--- a/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePlugin.java
+++ b/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePlugin.java
@@ -1,12 +1,12 @@
package io.github.fvarrui.javapackager.gradle;
-import edu.sc.seis.launch4j.tasks.Launch4jLibraryTask;
-import io.github.fvarrui.javapackager.packagers.Context;
-import io.github.fvarrui.javapackager.utils.Logger;
+import java.util.UUID;
+
import org.gradle.api.Plugin;
import org.gradle.api.Project;
-import java.util.UUID;
+import edu.sc.seis.launch4j.tasks.Launch4jLibraryTask;
+import io.github.fvarrui.javapackager.packagers.Context;
/**
* JavaPackager Gradle plugin
@@ -25,7 +25,7 @@ public void apply(Project project) {
project.getPluginManager().apply("edu.sc.seis.launch4j");
project.getExtensions().create(SETTINGS_EXT_NAME, PackagePluginExtension.class, project);
- project.getTasks().create(PACKAGE_TASK_NAME, DefaultPackageTask.class).dependsOn("build");
+ project.getTasks().create(PACKAGE_TASK_NAME, PackageTask.class).dependsOn("build");
Context.getGradleContext().setLibraryTask(project.getTasks().create("launch4j_" + UUID.randomUUID(), Launch4jLibraryTask.class));
diff --git a/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePluginExtension.java b/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePluginExtension.java
index 7e8179b7..da793647 100644
--- a/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePluginExtension.java
+++ b/src/main/java/io/github/fvarrui/javapackager/gradle/PackagePluginExtension.java
@@ -5,6 +5,7 @@
import java.util.HashMap;
import org.gradle.api.Project;
+import org.gradle.api.file.DuplicatesStrategy;
import groovy.lang.Closure;
import io.github.fvarrui.javapackager.model.Arch;
@@ -22,6 +23,7 @@
public class PackagePluginExtension extends PackagerSettings {
private Project project;
+ private DuplicatesStrategy duplicatesStrategy;
public PackagePluginExtension(Project project) {
super();
@@ -54,6 +56,7 @@ public PackagePluginExtension(Project project) {
this.scripts = new Scripts();
this.forceInstaller = false;
this.arch = Arch.getDefault();
+ this.duplicatesStrategy = DuplicatesStrategy.WARN;
}
public LinuxConfig linuxConfig(Closure closure) {
@@ -85,5 +88,13 @@ public Scripts scripts(Closure closure) {
project.configure(scripts, closure);
return scripts;
}
+
+ public void setDuplicatesStrategy(DuplicatesStrategy duplicatesStrategy) {
+ this.duplicatesStrategy = duplicatesStrategy;
+ }
+
+ public DuplicatesStrategy getDuplicatesStrategy() {
+ return duplicatesStrategy;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/io/github/fvarrui/javapackager/gradle/PackageTask.java b/src/main/java/io/github/fvarrui/javapackager/gradle/PackageTask.java
index de430227..ce6a321a 100644
--- a/src/main/java/io/github/fvarrui/javapackager/gradle/PackageTask.java
+++ b/src/main/java/io/github/fvarrui/javapackager/gradle/PackageTask.java
@@ -7,6 +7,7 @@
import java.util.List;
import java.util.Map;
+import org.gradle.api.file.DuplicatesStrategy;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.InputFile;
@@ -21,6 +22,7 @@
import io.github.fvarrui.javapackager.model.Manifest;
import io.github.fvarrui.javapackager.model.Platform;
import io.github.fvarrui.javapackager.model.Scripts;
+import io.github.fvarrui.javapackager.model.Template;
import io.github.fvarrui.javapackager.model.WindowsConfig;
import io.github.fvarrui.javapackager.packagers.Context;
import io.github.fvarrui.javapackager.packagers.Packager;
@@ -572,6 +574,30 @@ public Arch getArch() {
public void setArch(Arch arch) {
this.arch = arch;
}
+
+ @Input
+ @Optional
+ private List templates;
+
+ public List getTemplates() {
+ return templates;
+ }
+
+ public void setTemplates(List templates) {
+ this.templates = templates;
+ }
+
+ @Input
+ @Optional
+ private DuplicatesStrategy duplicatesStrategy;
+
+ public DuplicatesStrategy getDuplicatesStrategy() {
+ return duplicatesStrategy;
+ }
+
+ public void setDuplicatesStrategy(DuplicatesStrategy duplicatesStrategy) {
+ this.duplicatesStrategy = duplicatesStrategy;
+ }
// ===============
// create packager
@@ -583,6 +609,8 @@ protected Packager createPackager() throws Exception {
PackagePluginExtension extension = getProject().getExtensions().findByType(PackagePluginExtension.class);
+ Context.getGradleContext().setDuplicatesStrategy(defaultIfNull(duplicatesStrategy, extension.getDuplicatesStrategy()));
+
return
(Packager) PackagerFactory
.createPackager(defaultIfNull(platform, extension.getPlatform()))
@@ -623,6 +651,7 @@ protected Packager createPackager() throws Exception {
.packagingJdk(defaultIfNull(packagingJdk, extension.getPackagingJdk(), Context.getGradleContext().getDefaultToolchain()))
.runnableJar(defaultIfNull(runnableJar, extension.getRunnableJar()))
.scripts(defaultIfNull(scripts, extension.getScripts()))
+ .templates(defaultIfNull(templates, extension.getTemplates()))
.useResourcesAsWorkingDir(defaultIfNull(useResourcesAsWorkingDir, extension.isUseResourcesAsWorkingDir()))
.url(defaultIfNull(url, extension.getUrl()))
.version(defaultIfNull(version, extension.getVersion(), getProject().getVersion().toString()))
diff --git a/src/main/java/io/github/fvarrui/javapackager/maven/CreateRunnableJar.java b/src/main/java/io/github/fvarrui/javapackager/maven/CreateRunnableJar.java
index 3760ea38..602a11fe 100644
--- a/src/main/java/io/github/fvarrui/javapackager/maven/CreateRunnableJar.java
+++ b/src/main/java/io/github/fvarrui/javapackager/maven/CreateRunnableJar.java
@@ -38,14 +38,10 @@ public CreateRunnableJar() {
protected File doApply(Packager packager) {
String classifier = "runnable";
- String name = packager.getName();
- String version = packager.getVersion();
String mainClass = packager.getMainClass();
File outputDirectory = packager.getOutputDirectory();
ExecutionEnvironment env = Context.getMavenContext().getEnv();
Manifest manifest = packager.getManifest();
-
- File jarFile = new File(outputDirectory, name + "-" + version + "-" + classifier + ".jar");
List archive = new ArrayList<>();
archive.add(
@@ -80,17 +76,17 @@ protected File doApply(Packager packager) {
plugin(
groupId("org.apache.maven.plugins"),
artifactId("maven-jar-plugin"),
- version("3.1.1")
+ version("3.3.0")
),
goal("jar"),
configuration(
element("classifier", classifier),
element("archive", archive.toArray(new Element[archive.size()])),
- element("outputDirectory", jarFile.getParentFile().getAbsolutePath()),
- element("finalName", name + "-" + version)
+ element("outputDirectory", outputDirectory.getAbsolutePath())
),
- env);
-
+ env
+ );
+
} catch (MojoExecutionException e) {
Logger.error("Runnable jar creation failed! " + e.getMessage());
@@ -98,7 +94,12 @@ protected File doApply(Packager packager) {
}
- return jarFile;
+ // gets build.finalName value
+ String finalName = Context.getMavenContext().getEnv().getMavenProject().getBuild().getFinalName();
+
+ // creates file pointing to generated jar file
+ return new File(outputDirectory, finalName + "-" + classifier + ".jar");
+
}
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/maven/CreateTarball.java b/src/main/java/io/github/fvarrui/javapackager/maven/CreateTarball.java
index 95203093..1e59a4e4 100644
--- a/src/main/java/io/github/fvarrui/javapackager/maven/CreateTarball.java
+++ b/src/main/java/io/github/fvarrui/javapackager/maven/CreateTarball.java
@@ -35,8 +35,6 @@ public boolean skip(Packager packager) {
protected File doApply(Packager packager) {
File assetsFolder = packager.getAssetsFolder();
- String name = packager.getName();
- String version = packager.getVersion();
Platform platform = packager.getPlatform();
File outputDirectory = packager.getOutputDirectory();
@@ -46,8 +44,7 @@ protected File doApply(Packager packager) {
File assemblyFile = new File(assetsFolder, "assembly-tarball-" + platform + ".xml");
VelocityUtils.render(platform + "/assembly.xml.vtl", assemblyFile, packager);
- // tgz file name
- String finalName = packager.getTarballName() != null ? packager.getTarballName() : name + "-" + version + "-" + platform;
+ // output file format
String format = "tar.gz";
// invokes plugin to assemble tarball
@@ -62,13 +59,23 @@ protected File doApply(Packager packager) {
element("outputDirectory", outputDirectory.getAbsolutePath()),
element("formats", element("format", format)),
element("descriptors", element("descriptor", assemblyFile.getAbsolutePath())),
- element("finalName", finalName),
element("appendAssemblyId", "false")
),
Context.getMavenContext().getEnv()
);
- return new File(outputDirectory, finalName + "." + format);
+ // get generated filename
+ String finalName = Context.getMavenContext().getEnv().getMavenProject().getBuild().getFinalName();
+ File finalFile = new File(outputDirectory, finalName + "." + format);
+
+ // get desired file name
+ String tarName = packager.getTarballName() != null ? packager.getTarballName() : finalName + "-" + platform;
+ File tarFile = new File(outputDirectory, tarName + "." + format);
+
+ // rename generated to desired
+ finalFile.renameTo(tarFile);
+
+ return tarFile;
} catch (Exception e) {
diff --git a/src/main/java/io/github/fvarrui/javapackager/maven/CreateWindowsExeLaunch4j.java b/src/main/java/io/github/fvarrui/javapackager/maven/CreateWindowsExeLaunch4j.java
index 75ec624f..f999376e 100644
--- a/src/main/java/io/github/fvarrui/javapackager/maven/CreateWindowsExeLaunch4j.java
+++ b/src/main/java/io/github/fvarrui/javapackager/maven/CreateWindowsExeLaunch4j.java
@@ -14,15 +14,18 @@
import java.util.List;
import java.util.stream.Collectors;
+import net.jsign.WindowsSigner;
import org.apache.commons.lang3.StringUtils;
import org.twdata.maven.mojoexecutor.MojoExecutor.Element;
+import io.github.fvarrui.javapackager.model.Arch;
import io.github.fvarrui.javapackager.model.WindowsConfig;
import io.github.fvarrui.javapackager.model.WindowsExeCreationTool;
import io.github.fvarrui.javapackager.packagers.AbstractCreateWindowsExe;
import io.github.fvarrui.javapackager.packagers.Context;
import io.github.fvarrui.javapackager.packagers.WindowsPackager;
import io.github.fvarrui.javapackager.utils.FileUtils;
+import io.github.fvarrui.javapackager.utils.Logger;
/**
* Creates Windows executable with Maven
@@ -47,9 +50,15 @@ protected File doApply(WindowsPackager packager) throws Exception {
String jreMinVersion = packager.getJreMinVersion();
File jarFile = packager.getJarFile();
File appFolder = packager.getAppFolder();
+ Arch arch = packager.getArch();
createAssets(packager);
+ // warns about architecture
+ if (arch != Arch.x86) {
+ Logger.warn("Launch4J only can generate 32-bit executable");
+ }
+
// copies JAR to app folder
String jarPath;
if (winConfig.isWrapJar()) {
@@ -58,11 +67,9 @@ protected File doApply(WindowsPackager packager) throws Exception {
FileUtils.copyFileToFolder(jarFile, appFolder);
jarPath = jarFile.getName();
}
-
- List optsElements = vmArgs.stream().map(arg -> element("opt", arg)).collect(Collectors.toList());
-
- List jreElements = new ArrayList<>();
- jreElements.add(element("opts", optsElements.toArray(new Element[optsElements.size()])));
+
+ List jreElements = new ArrayList<>();
+ jreElements.add(element("opts", vmArgs.stream().map(arg -> element("opt", arg)).toArray(Element[]::new)));
jreElements.add(element("path", bundleJre ? jreDirectoryName : "%JAVA_HOME%;%PATH%"));
if (!StringUtils.isBlank(jreMinVersion)) {
jreElements.add(element("minVersion", jreMinVersion));
@@ -83,7 +90,7 @@ protected File doApply(WindowsPackager packager) throws Exception {
)
);
pluginConfig.add(element("chdir", useResourcesAsWorkingDir ? "." : ""));
- pluginConfig.add(element("jre", jreElements.toArray(new Element[jreElements.size()])));
+ pluginConfig.add(element("jre", jreElements.toArray(new Element[0])));
pluginConfig.add(
element("versionInfo",
element("fileVersion", winConfig.getFileVersion()),
@@ -108,17 +115,15 @@ protected File doApply(WindowsPackager packager) throws Exception {
plugin(
groupId("com.akathist.maven.plugins.launch4j"),
artifactId("launch4j-maven-plugin"),
- version("2.1.1")
+ version("2.4.1")
),
goal("launch4j"),
- configuration(pluginConfig.toArray(new Element[pluginConfig.size()])),
+ configuration(pluginConfig.toArray(new Element[0])),
Context.getMavenContext().getEnv()
);
-
- sign(getGenericExe(), packager);
-
+
FileUtils.copyFileToFile(getGenericExe(), executable);
-
+
} catch (Exception ex) {
throw new RuntimeException(ex);
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/maven/CreateZipball.java b/src/main/java/io/github/fvarrui/javapackager/maven/CreateZipball.java
index e823aa83..ead5c201 100644
--- a/src/main/java/io/github/fvarrui/javapackager/maven/CreateZipball.java
+++ b/src/main/java/io/github/fvarrui/javapackager/maven/CreateZipball.java
@@ -35,8 +35,6 @@ public boolean skip(Packager packager) {
protected File doApply(Packager packager) {
File assetsFolder = packager.getAssetsFolder();
- String name = packager.getName();
- String version = packager.getVersion();
Platform platform = packager.getPlatform();
File outputDirectory = packager.getOutputDirectory();
@@ -47,7 +45,6 @@ protected File doApply(Packager packager) {
VelocityUtils.render(platform + "/assembly.xml.vtl", assemblyFile, packager);
// zip file name and format
- String finalName = packager.getZipballName() != null ? packager.getZipballName() : name + "-" + version + "-" + platform;
String format = "zip";
// invokes plugin to assemble zipball and/or tarball
@@ -62,13 +59,23 @@ protected File doApply(Packager packager) {
element("outputDirectory", outputDirectory.getAbsolutePath()),
element("formats", element("format", format)),
element("descriptors", element("descriptor", assemblyFile.getAbsolutePath())),
- element("finalName", finalName),
element("appendAssemblyId", "false")
),
Context.getMavenContext().getEnv()
);
- return new File(outputDirectory, finalName + "." + format);
+ // gets generated filename
+ String finalName = Context.getMavenContext().getEnv().getMavenProject().getBuild().getFinalName();
+ File finalFile = new File(outputDirectory, finalName + "." + format);
+
+ // gets desired file name
+ String zipName = packager.getZipballName() != null ? packager.getZipballName() : finalName + "-" + platform;
+ File zipFile = new File(outputDirectory, zipName + "." + format);
+
+ // rename generated to desired
+ finalFile.renameTo(zipFile);
+
+ return zipFile;
} catch (Exception e) {
diff --git a/src/main/java/io/github/fvarrui/javapackager/maven/MavenContext.java b/src/main/java/io/github/fvarrui/javapackager/maven/MavenContext.java
index 49506334..91f6b757 100644
--- a/src/main/java/io/github/fvarrui/javapackager/maven/MavenContext.java
+++ b/src/main/java/io/github/fvarrui/javapackager/maven/MavenContext.java
@@ -1,11 +1,21 @@
package io.github.fvarrui.javapackager.maven;
import java.io.File;
+import java.time.Year;
-import io.github.fvarrui.javapackager.packagers.*;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.model.Organization;
import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
import org.twdata.maven.mojoexecutor.MojoExecutor.ExecutionEnvironment;
+import io.github.fvarrui.javapackager.packagers.AbstractCreateWindowsExe;
+import io.github.fvarrui.javapackager.packagers.Context;
+import io.github.fvarrui.javapackager.packagers.CreateWindowsExeWhy;
+import io.github.fvarrui.javapackager.packagers.CreateWindowsExeWinRun4j;
+import io.github.fvarrui.javapackager.packagers.Packager;
+import io.github.fvarrui.javapackager.packagers.WindowsPackager;
+
/**
* Maven context
*/
@@ -18,6 +28,24 @@ public MavenContext(ExecutionEnvironment env, Log logger) {
super();
this.env = env;
this.logger = logger;
+
+ // initialize some default params on project (avoid launch4j-maven-plugin warnings)
+ MavenProject project = env.getMavenProject();
+ if (project.getOrganization() == null) {
+ project.setOrganization(new Organization());
+ }
+ // set default organization name
+ if (StringUtils.isBlank(project.getOrganization().getName())) {
+ project.getOrganization().setName(Packager.DEFAULT_ORGANIZATION_NAME);
+ }
+ // set default inception year
+ if (StringUtils.isBlank(project.getInceptionYear())) {
+ project.setInceptionYear(Year.now().toString());
+ }
+ // set default description
+ if (StringUtils.isBlank(project.getDescription())) {
+ project.setDescription(project.getArtifactId());
+ }
}
public ExecutionEnvironment getEnv() {
@@ -77,7 +105,5 @@ public File createWindowsExe(WindowsPackager packager) throws Exception {
}
return null;
}
-
-
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/maven/PackageMojo.java b/src/main/java/io/github/fvarrui/javapackager/maven/PackageMojo.java
index 6ce9fe45..78d54203 100644
--- a/src/main/java/io/github/fvarrui/javapackager/maven/PackageMojo.java
+++ b/src/main/java/io/github/fvarrui/javapackager/maven/PackageMojo.java
@@ -321,6 +321,12 @@ public class PackageMojo extends AbstractMojo {
*/
@Parameter(property = "arch", required = false)
private Arch arch;
+
+ /**
+ * Templates configuration
+ */
+ @Parameter(property = "templates", required = false)
+ private List templates;
public void execute() throws MojoExecutionException {
@@ -376,6 +382,7 @@ public void execute() throws MojoExecutionException {
.packagingJdk(packagingJdk)
.runnableJar(runnableJar)
.scripts(scripts)
+ .templates(templates)
.useResourcesAsWorkingDir(useResourcesAsWorkingDir)
.url(url)
.version(version)
diff --git a/src/main/java/io/github/fvarrui/javapackager/maven/ResolveLicenseFromPOM.java b/src/main/java/io/github/fvarrui/javapackager/maven/ResolveLicenseFromPOM.java
index d3498ae5..9316fa92 100644
--- a/src/main/java/io/github/fvarrui/javapackager/maven/ResolveLicenseFromPOM.java
+++ b/src/main/java/io/github/fvarrui/javapackager/maven/ResolveLicenseFromPOM.java
@@ -1,8 +1,9 @@
package io.github.fvarrui.javapackager.maven;
import java.io.File;
-import java.io.IOException;
import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
@@ -36,13 +37,13 @@ protected File doApply(Packager packager) {
String urlStr = null;
try {
urlStr = licenses.get(0).getUrl();
- URL licenseUrl = new URL(urlStr);
+ URL licenseUrl = new URI(urlStr).toURL();
licenseFile = new File(assetsFolder, "LICENSE");
FileUtils.downloadFromUrl(licenseUrl, licenseFile);
- } catch (MalformedURLException e) {
+ } catch (URISyntaxException | MalformedURLException e) {
Logger.error("Invalid license URL specified: " + urlStr);
licenseFile = null;
- } catch (IOException e) {
+ } catch (Exception e) {
Logger.error("Cannot download license from " + urlStr);
licenseFile = null;
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/model/Arch.java b/src/main/java/io/github/fvarrui/javapackager/model/Arch.java
index 586bc6c7..b00887dc 100644
--- a/src/main/java/io/github/fvarrui/javapackager/model/Arch.java
+++ b/src/main/java/io/github/fvarrui/javapackager/model/Arch.java
@@ -1,30 +1,15 @@
package io.github.fvarrui.javapackager.model;
import org.apache.commons.lang3.SystemUtils;
+import org.redline_rpm.header.Architecture;
public enum Arch {
- aarch64("arm64", "AARCH64"),
- x64("amd64", "X86_64"),
- x86("i386", "i386");
-
- private String deb;
- private String rpm;
-
- Arch(String deb, String rpm) {
- this.deb = deb;
- this.rpm = rpm;
- }
-
- public String getDeb() {
- return deb;
- }
-
- public String getRpm() {
- return rpm;
- }
+ aarch64,
+ x64,
+ x86;
- public static Arch getDefault() {
- switch (SystemUtils.OS_ARCH) {
+ public static Arch getArch(String archString) {
+ switch (archString) {
case "x86":
case "i386":
case "i486":
@@ -37,8 +22,39 @@ public static Arch getDefault() {
case "aarch64":
return aarch64;
default:
- throw new IllegalArgumentException("Unknown architecture " + SystemUtils.OS_ARCH);
+ throw new IllegalArgumentException("Unknown architecture " + archString);
+ }
+ }
+
+ public static Arch getDefault() {
+ return getArch(SystemUtils.OS_ARCH);
+ }
+
+ public String toDebArchitecture() {
+ switch (this) {
+ case aarch64: return "arm64";
+ case x64: return "amd64";
+ case x86: return "i386";
+ default: return null;
+ }
+ }
+
+ public Architecture toRpmArchitecture() {
+ switch (this) {
+ case aarch64: return Architecture.AARCH64;
+ case x64: return Architecture.X86_64;
+ case x86: return Architecture.I386;
+ default: return null;
+ }
+ }
+
+ public String toMsiArchitecture() {
+ switch (this) {
+ case aarch64: return "arm64";
+ case x64: return "x64";
+ case x86: return "x86";
+ default: return null;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/fvarrui/javapackager/model/LinuxConfig.java b/src/main/java/io/github/fvarrui/javapackager/model/LinuxConfig.java
index 74c39b75..f52507fe 100644
--- a/src/main/java/io/github/fvarrui/javapackager/model/LinuxConfig.java
+++ b/src/main/java/io/github/fvarrui/javapackager/model/LinuxConfig.java
@@ -3,8 +3,11 @@
import java.io.File;
import java.io.Serializable;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import org.apache.commons.lang3.ObjectUtils;
+
import io.github.fvarrui.javapackager.packagers.Packager;
/**
@@ -19,6 +22,7 @@ public class LinuxConfig implements Serializable {
private boolean generateAppImage = true;
private File pngFile;
private boolean wrapJar = true;
+ private String installationPath;
public void setCategories(List categories) {
this.categories = categories;
@@ -67,11 +71,20 @@ public boolean isWrapJar() {
public void setWrapJar(boolean wrapJar) {
this.wrapJar = wrapJar;
}
+
+ public String getInstallationPath() {
+ return installationPath;
+ }
+
+ public void setInstallationPath(String installationPath) {
+ this.installationPath = installationPath;
+ }
@Override
public String toString() {
return "LinuxConfig [categories=" + categories + ", generateDeb=" + generateDeb + ", generateRpm=" + generateRpm
- + ", generateAppImage=" + generateAppImage + ", pngFile=" + pngFile + ", wrapJar=" + wrapJar + "]";
+ + ", generateAppImage=" + generateAppImage + ", pngFile=" + pngFile + ", wrapJar=" + wrapJar
+ + ", installationPath=" + installationPath + "]";
}
/**
@@ -80,7 +93,8 @@ public String toString() {
* @param packager Packager
*/
public void setDefaults(Packager packager) {
- this.setCategories((categories == null || categories.isEmpty()) ? Arrays.asList("Utility") : categories);
+ this.setCategories((categories == null || categories.isEmpty()) ? Collections.singletonList("Utility") : categories);
+ this.setInstallationPath(ObjectUtils.defaultIfNull(installationPath, "/opt"));
}
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/model/MacConfig.java b/src/main/java/io/github/fvarrui/javapackager/model/MacConfig.java
index 71b9b261..2f28aec5 100644
--- a/src/main/java/io/github/fvarrui/javapackager/model/MacConfig.java
+++ b/src/main/java/io/github/fvarrui/javapackager/model/MacConfig.java
@@ -34,7 +34,12 @@ public class MacConfig implements Serializable {
private String developerId = "-";
private File entitlements;
private File provisionProfile;
+ private File customLauncher;
+ private File customInfoPlist;
+ private File customRuntimeInfoPlist;
private boolean codesignApp = true;
+ private boolean notarizeApp = false;
+ private String keyChainProfile;
private InfoPlist infoPlist = new InfoPlist();
private boolean hardenedCodesign = true;
private MacStartup macStartup = MacStartup.SCRIPT;
@@ -191,6 +196,30 @@ public void setDeveloperId(String developerId) {
this.developerId = developerId;
}
+ public File getCustomLauncher() {
+ return customLauncher;
+ }
+
+ public void setCustomLauncher(File customLauncher) {
+ this.customLauncher = customLauncher;
+ }
+
+ public File getCustomInfoPlist() {
+ return customInfoPlist;
+ }
+
+ public void setCustomInfoPlist(File customInfoPlist) {
+ this.customInfoPlist = customInfoPlist;
+ }
+
+ public File getCustomRuntimeInfoPlist() {
+ return customRuntimeInfoPlist;
+ }
+
+ public void setCustomRuntimeInfoPlist(File customRuntimeInfoPlist) {
+ this.customRuntimeInfoPlist = customRuntimeInfoPlist;
+ }
+
public File getProvisionProfile() {
return provisionProfile;
}
@@ -215,6 +244,22 @@ public void setCodesignApp(boolean codesignApp) {
this.codesignApp = codesignApp;
}
+ public boolean isNotarizeApp() {
+ return notarizeApp;
+ }
+
+ public void setNotarizeApp(boolean notarizeApp) {
+ this.notarizeApp = notarizeApp;
+ }
+
+ public String getKeyChainProfile() {
+ return keyChainProfile;
+ }
+
+ public void setKeyChainProfile(String keyChainProfile) {
+ this.keyChainProfile = keyChainProfile;
+ }
+
public InfoPlist getInfoPlist() {
return infoPlist;
}
@@ -248,9 +293,10 @@ public String toString() {
+ ", volumeName=" + volumeName + ", generateDmg=" + generateDmg + ", generatePkg=" + generatePkg
+ ", relocateJar=" + relocateJar + ", appId=" + appId + ", developerId=" + developerId
+ ", entitlements=" + entitlements + ", provisionProfile=" + provisionProfile + ", customLauncher="
- + customLauncher + ", customInfoPlist=" + customInfoPlist + ", codesignApp=" + codesignApp
- + ", infoPlist=" + infoPlist + ", hardenedCodesign=" + hardenedCodesign + ", macStartup=" + macStartup
- + "]";
+ + customLauncher + ", customInfoPlist=" + customInfoPlist + ", customRuntimeInfoPlist="
+ + customRuntimeInfoPlist + ", codesignApp=" + codesignApp + ", notarizeApp=" + notarizeApp
+ + ", keyChainProfile=" + keyChainProfile + ", infoPlist=" + infoPlist + ", hardenedCodesign="
+ + hardenedCodesign + ", macStartup=" + macStartup + "]";
}
/**
diff --git a/src/main/java/io/github/fvarrui/javapackager/model/Platform.java b/src/main/java/io/github/fvarrui/javapackager/model/Platform.java
index da856e1f..6fb5a1c6 100644
--- a/src/main/java/io/github/fvarrui/javapackager/model/Platform.java
+++ b/src/main/java/io/github/fvarrui/javapackager/model/Platform.java
@@ -23,4 +23,13 @@ public static Platform getCurrentPlatform() {
return null;
}
+ public static Platform getPlatform(String platformString) {
+ switch (platformString.toLowerCase()) {
+ case "linux": return linux;
+ case "darwin": return mac;
+ case "windows": return windows;
+ default: throw new IllegalArgumentException("Unknown platform " + platformString);
+ }
+ }
+
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/model/Template.java b/src/main/java/io/github/fvarrui/javapackager/model/Template.java
new file mode 100644
index 00000000..b06274ce
--- /dev/null
+++ b/src/main/java/io/github/fvarrui/javapackager/model/Template.java
@@ -0,0 +1,36 @@
+package io.github.fvarrui.javapackager.model;
+
+public class Template {
+
+ private String name;
+ private boolean bom = false;
+
+ public Template() {}
+
+ public Template(String name, boolean bom) {
+ this.name = name;
+ this.bom = bom;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isBom() {
+ return bom;
+ }
+
+ public void setBom(boolean bom) {
+ this.bom = bom;
+ }
+
+ @Override
+ public String toString() {
+ return "Template [name=" + name + ", bom=" + bom + "]";
+ }
+
+}
diff --git a/src/main/java/io/github/fvarrui/javapackager/model/WindowsConfig.java b/src/main/java/io/github/fvarrui/javapackager/model/WindowsConfig.java
index 8f7637e3..cdf040cd 100644
--- a/src/main/java/io/github/fvarrui/javapackager/model/WindowsConfig.java
+++ b/src/main/java/io/github/fvarrui/javapackager/model/WindowsConfig.java
@@ -1,5 +1,6 @@
package io.github.fvarrui.javapackager.model;
+import static io.github.fvarrui.javapackager.utils.ObjectUtils.defaultIfNull;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import java.io.File;
@@ -7,8 +8,9 @@
import java.util.LinkedHashMap;
import java.util.UUID;
+import org.apache.commons.collections4.MapUtils;
+
import io.github.fvarrui.javapackager.packagers.Packager;
-import io.github.fvarrui.javapackager.utils.ObjectUtils;
/**
* JavaPackager Windows specific configuration
@@ -30,6 +32,7 @@ public class WindowsConfig implements Serializable {
private String trademarks;
private String txtFileVersion;
private String txtProductVersion;
+ private String shortcutName;
private boolean disableDirPage = true;
private boolean disableProgramGroupPage = true;
private boolean disableFinishedPage = true;
@@ -153,6 +156,14 @@ public void setTxtProductVersion(String txtProductVersion) {
this.txtProductVersion = txtProductVersion;
}
+ public String getShortcutName() {
+ return shortcutName;
+ }
+
+ public void setShortcutName(String shortcutName) {
+ this.shortcutName = shortcutName;
+ }
+
public String getInternalName() {
return internalName;
}
@@ -312,6 +323,7 @@ public String toString() {
+ ", internalName=" + internalName + ", language=" + language + ", originalFilename=" + originalFilename
+ ", productName=" + productName + ", productVersion=" + productVersion + ", trademarks=" + trademarks
+ ", txtFileVersion=" + txtFileVersion + ", txtProductVersion=" + txtProductVersion
+ + ", shortcutName=" + shortcutName
+ ", disableDirPage=" + disableDirPage + ", disableProgramGroupPage=" + disableProgramGroupPage
+ ", disableFinishedPage=" + disableFinishedPage + ", disableRunAfterInstall=" + disableRunAfterInstall
+ ", disableWelcomePage=" + disableWelcomePage + ", createDesktopIconTask=" + createDesktopIconTask
@@ -327,18 +339,25 @@ public String toString() {
* @param packager Packager
*/
public void setDefaults(Packager packager) {
- this.setHeaderType(ObjectUtils.defaultIfNull(this.getHeaderType(), HeaderType.gui));
+ this.setHeaderType(defaultIfNull(this.getHeaderType(), HeaderType.gui));
this.setFileVersion(defaultIfBlank(this.getFileVersion(), "1.0.0.0"));
this.setTxtFileVersion(defaultIfBlank(this.getTxtFileVersion(), "" + packager.getVersion()));
this.setProductVersion(defaultIfBlank(this.getProductVersion(), "1.0.0.0"));
+ this.setShortcutName(defaultIfBlank(this.getShortcutName(), packager.getDisplayName()));
this.setTxtProductVersion(defaultIfBlank(this.getTxtProductVersion(), "" + packager.getVersion()));
this.setCompanyName(defaultIfBlank(this.getCompanyName(), packager.getOrganizationName()));
+ this.setTrademarks(defaultIfBlank(this.getTrademarks(), packager.getOrganizationName()));
this.setCopyright(defaultIfBlank(this.getCopyright(), packager.getOrganizationName()));
this.setFileDescription(defaultIfBlank(this.getFileDescription(), packager.getDescription()));
this.setProductName(defaultIfBlank(this.getProductName(), packager.getName()));
this.setInternalName(defaultIfBlank(this.getInternalName(), packager.getName()));
this.setOriginalFilename(defaultIfBlank(this.getOriginalFilename(), packager.getName() + ".exe"));
this.setMsiUpgradeCode(defaultIfBlank(this.getMsiUpgradeCode(), UUID.randomUUID().toString()));
+ // init setup languages
+ if (MapUtils.isEmpty(this.getSetupLanguages())) {
+ this.getSetupLanguages().put("english", "compiler:Default.isl");
+ this.getSetupLanguages().put("spanish", "compiler:Languages\\Spanish.isl");
+ }
}
-
+
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/AbstractCreateWindowsExe.java b/src/main/java/io/github/fvarrui/javapackager/packagers/AbstractCreateWindowsExe.java
index cf8615de..c70b026d 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/AbstractCreateWindowsExe.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/AbstractCreateWindowsExe.java
@@ -7,9 +7,9 @@
import io.github.fvarrui.javapackager.utils.FileUtils;
import io.github.fvarrui.javapackager.utils.VelocityUtils;
-public abstract class AbstractCreateWindowsExe extends WindowsArtifactGenerator {
+public abstract class AbstractCreateWindowsExe extends ArtifactGenerator {
- private File outputFolder;
+ private final File outputFolder;
private File genericManifest;
private File genericIcon;
private File genericJar;
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/BundleJre.java b/src/main/java/io/github/fvarrui/javapackager/packagers/BundleJre.java
index b26ad175..ba686814 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/BundleJre.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/BundleJre.java
@@ -4,23 +4,28 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import io.github.fvarrui.javapackager.model.Platform;
-import io.github.fvarrui.javapackager.utils.CommandUtils;
import io.github.fvarrui.javapackager.utils.FileUtils;
import io.github.fvarrui.javapackager.utils.JDKUtils;
import io.github.fvarrui.javapackager.utils.Logger;
import io.github.fvarrui.javapackager.utils.VersionUtils;
+import static io.github.fvarrui.javapackager.utils.CommandUtils.execute;
+
+
/**
- * Bundles a Java Runtime Enrironment (JRE) with the app
+ * Bundles a Java Runtime Environment (JRE) with the app
*/
public class BundleJre extends ArtifactGenerator {
+ private static final String ALL_MODULES = "ALL-MODULE-PATH";
+
public BundleJre() {
super("JRE");
}
@@ -56,23 +61,32 @@ protected File doApply(Packager packager) throws Exception {
throw new Exception("'" + specificJreFolder + "' is not a directory!");
}
- // checks if the specified jre is valid (it looks for 'release' file into it, and if so, checks if it matches the right platform
+ // checks if the specified jre is valid (it looks for 'release' file into it, and if so, checks if it matches the right platform
+ boolean validJre = true;
if (!JDKUtils.isValidJRE(platform, specificJreFolder)) {
- Logger.warn("An invalid JRE may have been specified for '" + platform + "' platform: " + specificJreFolder + " ('release' file not found)");
-
- // try to fix the path to the JRE on MacOS adding Contents/Home to JRE path
+ // if platform is mac
if (platform.equals(Platform.mac)) {
+ // try to fix the path to the JRE on MacOS adding Contents/Home to JRE path
File fixedJreFolder = new File(specificJreFolder, "Contents/Home");
if (JDKUtils.isValidJRE(platform, fixedJreFolder)) {
specificJreFolder = fixedJreFolder;
- Logger.warn("Specified 'jrePath' fixed: " + specificJreFolder);
+ Logger.warn("Specified 'jrePath' fixed: " + specificJreFolder);
+ } else {
+ validJre = false;
}
+ } else {
+ validJre = false;
}
}
+ if (!validJre) {
+ Logger.warn("An invalid JRE may have been specified for '" + platform + "' platform: " + specificJreFolder);
+ } else if (JDKUtils.isJDK(specificJreFolder)) {
+ Logger.warn("Wow! Embedding a JDK instead of a JRE ... are you sure you want to do that?");
+ }
// removes old jre folder from bundle
if (destinationFolder.exists()) FileUtils.removeFolder(destinationFolder);
@@ -122,20 +136,29 @@ protected File doApply(Packager packager) throws Exception {
Logger.info("Using " + modulesDir + " modules directory");
if (destinationFolder.exists()) FileUtils.removeFolder(destinationFolder);
+
+ // gets JDK release info
+ Map releaseMap = JDKUtils.getRelease(jdkPath);
+ String releaseInfo = "add:IMAGE_TYPE=\"JRE\":OS_ARCH=\"" + releaseMap.get("OS_ARCH") + "\":OS_NAME=\"" + releaseMap.get("OS_NAME") + "\"";
+ // full path to jlink command
File jlink = new File(currentJdk, "/bin/jlink");
+ List modulePaths = new ArrayList();
+ modulePaths.add(modulesDir);
+ modulePaths.addAll(additionalModulePaths);
+
// generates customized jre using modules
- CommandUtils.execute(
+ execute(
jlink,
- "--module-path", modulesDir,
- additionalModulePathsToParams(additionalModulePaths),
+ "--module-path=" + StringUtils.join(modulePaths, File.pathSeparator),
"--add-modules", modules,
"--output", destinationFolder,
"--no-header-files",
"--no-man-pages",
- "--strip-debug",
- "--compress=2"
+ "--strip-debug",
+ "--release-info", releaseInfo,
+ (VersionUtils.getJavaMajorVersion() < 21 ? "--compress=2" : null)
);
// sets execution permissions on executables in jre
@@ -163,7 +186,7 @@ protected File doApply(Packager packager) throws Exception {
}
// updates bundle jre property value, as this artifact generator could disable this option
- // (e.g. when bundling a jre from a different platform than the current one)
+ // (e.g., when bundling a jre from a different platform than the current one)
packager.bundleJre(bundleJre);
return destinationFolder;
@@ -186,16 +209,15 @@ protected String getRequiredModules(File packagingJdk, File libsFolder, boolean
Logger.infoIndent("Getting required modules ... ");
File jdeps = new File(packagingJdk, "/bin/jdeps");
-
- File jarLibs = null;
- if (libsFolder != null && libsFolder.exists())
- jarLibs = new File(libsFolder, "*.jar");
- else
- Logger.warn("No dependencies found!");
+ List modulePaths = getModulePaths(jarFile, libsFolder, additionalModulePaths);
List modulesList;
- if (customizedJre && defaultModules != null && !defaultModules.isEmpty()) {
+ if (!customizedJre) {
+
+ return ALL_MODULES;
+
+ } else if (defaultModules != null && !defaultModules.isEmpty()) {
modulesList =
defaultModules
@@ -203,18 +225,17 @@ protected String getRequiredModules(File packagingJdk, File libsFolder, boolean
.map(module -> module.trim())
.collect(Collectors.toList());
- } else if (customizedJre && VersionUtils.getJavaMajorVersion() >= 13) {
+ } else if (VersionUtils.getJavaMajorVersion() >= 13) {
String modules =
- CommandUtils.execute(
- jdeps.getAbsolutePath(),
+ execute(
+ jdeps,
"-q",
"--multi-release", VersionUtils.getJavaMajorVersion(),
"--ignore-missing-deps",
"--print-module-deps",
- additionalModulePathsToParams(additionalModulePaths),
- jarLibs,
- jarFile
+ "--add-modules=ALL-MODULE-PATH",
+ "--module-path=" + StringUtils.join(modulePaths, File.pathSeparator)
);
modulesList =
@@ -224,18 +245,17 @@ protected String getRequiredModules(File packagingJdk, File libsFolder, boolean
.filter(module -> !module.isEmpty())
.collect(Collectors.toList());
- } else if (customizedJre && VersionUtils.getJavaMajorVersion() >= 9) {
+ } else if (VersionUtils.getJavaMajorVersion() >= 9) {
String modules =
- CommandUtils.execute(
+ execute(
jdeps.getAbsolutePath(),
"-q",
"--multi-release", VersionUtils.getJavaMajorVersion(),
"--ignore-missing-deps",
"--list-deps",
- additionalModulePathsToParams(additionalModulePaths),
- jarLibs,
- jarFile
+ "--add-modules=ALL-MODULE-PATH",
+ "--module-path=" + StringUtils.join(modulePaths, File.pathSeparator)
);
modulesList =
@@ -256,7 +276,7 @@ protected String getRequiredModules(File packagingJdk, File libsFolder, boolean
if (modulesList.isEmpty()) {
Logger.warn("It was not possible to determine the necessary modules. All modules will be included");
- modulesList.add("ALL-MODULE-PATH");
+ modulesList.add(ALL_MODULES);
} else {
modulesList.addAll(additionalModules);
}
@@ -266,23 +286,21 @@ protected String getRequiredModules(File packagingJdk, File libsFolder, boolean
return StringUtils.join(modulesList, ",");
}
- private String [] additionalModulePathsToParams(List additionalModulePaths) {
-
- List additionalPaths = new ArrayList<>();
-
- additionalModulePaths
- .stream()
- .filter(path -> {
- if (path.exists()) return true;
- Logger.warn("Additional module path not found: " + path);
- return false;
- })
- .forEach(path -> {
- additionalPaths.add("--module-path");
- additionalPaths.add(path.toString());
- });
-
- return additionalPaths.toArray(new String[0]);
+ private List getModulePaths(File jarFile, File libsFolder, List additionalModulePaths) {
+ List modulePaths = new ArrayList<>();
+ modulePaths.add(jarFile);
+ modulePaths.add(libsFolder);
+ modulePaths.addAll(
+ additionalModulePaths
+ .stream()
+ .filter(path -> {
+ if (path.exists()) return true;
+ Logger.warn("Additional module path not found: " + path);
+ return false;
+ })
+ .collect(Collectors.toList())
+ );
+ return modulePaths;
}
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/Context.java b/src/main/java/io/github/fvarrui/javapackager/packagers/Context.java
index be4527e0..e86ab4ed 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/Context.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/Context.java
@@ -79,7 +79,7 @@ public static boolean isGradle() {
return context instanceof GradleContext;
}
- public static MavenContext getMavenContext() {
+ public static MavenContext getMavenContext() {
return (MavenContext) context;
}
@@ -88,7 +88,10 @@ public static GradleContext getGradleContext() {
}
public File getDefaultToolchain() {
- return new File(System.getProperty("java.home")); // Use java.home as fallback
+ if (System.getenv("JAVA_HOME") != null) {
+ return new File(System.getenv("JAVA_HOME")); // Use JAVA_HOME as fallback
+ }
+ return new File(System.getProperty("java.home"));
}
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWhy.java b/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWhy.java
index 3c604208..e689e166 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWhy.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWhy.java
@@ -5,10 +5,11 @@
import io.github.fvarrui.javapackager.model.Platform;
import io.github.fvarrui.javapackager.model.WindowsConfig;
import io.github.fvarrui.javapackager.model.WindowsExeCreationTool;
-import io.github.fvarrui.javapackager.utils.CommandUtils;
import io.github.fvarrui.javapackager.utils.FileUtils;
import io.github.fvarrui.javapackager.utils.Logger;
+import io.github.fvarrui.javapackager.utils.RcEdit;
import io.github.fvarrui.javapackager.utils.VelocityUtils;
+import net.jsign.WindowsSigner;
/**
* Creates Windows executable with WinRun4j
@@ -33,7 +34,6 @@ public boolean skip(WindowsPackager packager) {
@Override
protected File doApply(WindowsPackager packager) throws Exception {
- String name = packager.getName();
File executable = packager.getExecutable();
File manifestFile = packager.getManifestFile();
File iconFile = packager.getIconFile();
@@ -56,25 +56,22 @@ protected File doApply(WindowsPackager packager) throws Exception {
// creates generic exe
FileUtils.copyResourceToFile("/windows/JavaLauncher.exe", getGenericExe(), packager.getAssetsDir());
- // copies rcedit command line tool (needed to manipulate exe)
- File rcedit = new File(getOutputFolder(), "rcedit.exe");
- FileUtils.copyResourceToFile("/windows/rcedit-x64.exe", rcedit);
-
// generates ini file
File genericIni = new File(getOutputFolder(), "launcher.ini");
VelocityUtils.render("windows/why-ini.vtl", genericIni, packager);
Logger.info("INI file generated in " + genericIni.getAbsolutePath() + "!");
- // process EXE with rcedit-x64.exe
- CommandUtils.execute(rcedit, getGenericExe(), "--set-icon", getGenericIcon());
- CommandUtils.execute(rcedit, getGenericExe(), "--application-manifest", getGenericManifest());
- CommandUtils.execute(rcedit, getGenericExe(), "--set-version-string", "FileDescription", name);
- CommandUtils.execute(rcedit, getGenericExe(), "--set-file-version", winConfig.getFileVersion());
- CommandUtils.execute(rcedit, getGenericExe(), "--set-product-version", winConfig.getProductVersion());
- CommandUtils.execute(rcedit, getGenericExe(), "--set-version-string", "CompanyName", winConfig.getCompanyName());
- CommandUtils.execute(rcedit, getGenericExe(), "--set-version-string", "InternalName", winConfig.getInternalName());
- CommandUtils.execute(rcedit, getGenericExe(), "--set-version-string", "OriginalFilename",winConfig.getOriginalFilename());
- CommandUtils.execute(rcedit, getGenericExe(), "--set-version-string", "ProductName", winConfig.getProductName());
+ // set exe metadata with rcedit
+ RcEdit rcedit = new RcEdit(getOutputFolder());
+ rcedit.setIcon(getGenericExe(), getGenericIcon());
+ rcedit.setManifest(getGenericExe(), getGenericManifest());
+ rcedit.setFileVersion(getGenericExe(), winConfig.getFileVersion());
+ rcedit.setProductVersion(getGenericExe(), winConfig.getProductVersion());
+ rcedit.setVersionString(getGenericExe(), "FileDescription", winConfig.getFileDescription());
+ rcedit.setVersionString(getGenericExe(), "CompanyName", winConfig.getCompanyName());
+ rcedit.setVersionString(getGenericExe(), "InternalName", winConfig.getInternalName());
+ rcedit.setVersionString(getGenericExe(), "OriginalFilename", winConfig.getOriginalFilename());
+ rcedit.setVersionString(getGenericExe(), "ProductName", winConfig.getProductName());
// copies JAR to app folder
FileUtils.copyFileToFolder(jarFile, appFolder);
@@ -82,9 +79,6 @@ protected File doApply(WindowsPackager packager) throws Exception {
// copies ini file to app folder
FileUtils.copyFileToFolder(genericIni, appFolder);
- // signs generated exe file
- sign(getGenericExe(), packager);
-
// copies exe file to app folder with apps name
FileUtils.copyFileToFile(getGenericExe(), executable);
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWinRun4j.java b/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWinRun4j.java
index 5f864d62..221a3669 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWinRun4j.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/CreateWindowsExeWinRun4j.java
@@ -1,21 +1,21 @@
package io.github.fvarrui.javapackager.packagers;
import java.io.File;
-import java.io.FileOutputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Optional;
-import java.util.Properties;
+import net.jsign.WindowsSigner;
import org.apache.commons.lang3.StringUtils;
+import io.github.fvarrui.javapackager.model.Arch;
import io.github.fvarrui.javapackager.model.Platform;
import io.github.fvarrui.javapackager.model.WindowsConfig;
import io.github.fvarrui.javapackager.model.WindowsExeCreationTool;
-import io.github.fvarrui.javapackager.utils.CommandUtils;
import io.github.fvarrui.javapackager.utils.FileUtils;
-import io.github.fvarrui.javapackager.utils.JarUtils;
+import io.github.fvarrui.javapackager.utils.JDKUtils;
import io.github.fvarrui.javapackager.utils.Logger;
+import io.github.fvarrui.javapackager.utils.RcEdit;
import io.github.fvarrui.javapackager.utils.VelocityUtils;
/**
@@ -51,13 +51,12 @@ protected File doApply(WindowsPackager packager) throws Exception {
File jarFile = packager.getJarFile();
File manifestFile = packager.getManifestFile();
File iconFile = packager.getIconFile();
- File libsFolder = packager.getLibsFolder();
File appFolder = packager.getAppFolder();
- String mainClass = packager.getMainClass();
File jreDestinationFolder = packager.getJreDestinationFolder();
boolean bundleJre = packager.getBundleJre();
String vmLocation = packager.getWinConfig().getVmLocation();
- WindowsConfig winConfig = packager.getWinConfig();
+ WindowsConfig winConfig = packager.getWinConfig();
+ Arch arch = packager.getArch();
if (winConfig.isWrapJar()) {
Logger.warn("'wrapJar' property ignored when building EXE with " + getArtifactName());
@@ -71,12 +70,17 @@ protected File doApply(WindowsPackager packager) throws Exception {
// creates generic manifest
FileUtils.copyFileToFile(iconFile, getGenericIcon());
- // creates generic exe
- FileUtils.copyResourceToFile("/windows/WinRun4J64.exe", getGenericExe());
+ // checks if target architecture matches JRE arch
+ if (bundleJre && !JDKUtils.isValidJRE(Platform.windows, arch, packager.getJreDestinationFolder())) {
+ throw new Exception("Bundled JRE must match " + Platform.windows + " " + arch);
+ }
- // copies rcedit command line tool (needed to manipulate exe)
- File rcedit = new File(getOutputFolder(), "rcedit.exe");
- FileUtils.copyResourceToFile("/windows/rcedit-x64.exe", rcedit);
+ // creates generic exe
+ if (arch == Arch.x86) {
+ FileUtils.copyResourceToFile("/windows/WinRun4J.exe", getGenericExe());
+ } else {
+ FileUtils.copyResourceToFile("/windows/WinRun4J64.exe", getGenericExe());
+ }
// uses vmLocation only if a JRE is bundled
if (bundleJre) {
@@ -93,7 +97,7 @@ protected File doApply(WindowsPackager packager) throws Exception {
} else {
- // searchs for valid jvm.dll file in JRE
+ // searchs for a valid jvm.dll file in JRE
Optional jvmDllFile = Arrays.asList(JVM_DLL_PATHS)
.stream()
.map(path -> new File(jreDestinationFolder, path))
@@ -119,39 +123,30 @@ protected File doApply(WindowsPackager packager) throws Exception {
}
- // generates ini file
- File genericIni = new File(getOutputFolder(), "app.ini");
- VelocityUtils.render("windows/ini.vtl", genericIni, packager);
- Logger.info("INI file generated in " + genericIni.getAbsolutePath() + "!");
-
- // process EXE with rcedit-x64.exe
- CommandUtils.execute(rcedit, getGenericExe(), "--set-icon", getGenericIcon());
- CommandUtils.execute(rcedit, getGenericExe(), "--application-manifest", getGenericManifest());
- CommandUtils.execute(rcedit, getGenericExe(), "--set-version-string", "FileDescription", name);
+ // set exe metadata with rcedit
+ RcEdit rcedit = new RcEdit(getOutputFolder());
+ rcedit.setIcon(getGenericExe(), getGenericIcon());
+ rcedit.setManifest(getGenericExe(), getGenericManifest());
+ rcedit.setFileVersion(getGenericExe(), winConfig.getFileVersion());
+ rcedit.setProductVersion(getGenericExe(), winConfig.getProductVersion());
+ rcedit.setVersionString(getGenericExe(), "FileDescription", winConfig.getFileDescription());
+ rcedit.setVersionString(getGenericExe(), "CompanyName", winConfig.getCompanyName());
+ rcedit.setVersionString(getGenericExe(), "InternalName", winConfig.getInternalName());
+ rcedit.setVersionString(getGenericExe(), "OriginalFilename", winConfig.getOriginalFilename());
+ rcedit.setVersionString(getGenericExe(), "ProductName", winConfig.getProductName());
// copies JAR to libs folder
FileUtils.copyFileToFolder(jarFile, appFolder);
- // copies winrun4j launcher helper library (needed to work around
- File winrun4jJar = new File(libsFolder, "winrun4j-launcher.jar");
- FileUtils.copyResourceToFile("/windows/winrun4j-launcher.jar", winrun4jJar);
-
- // generates winrun4j properties pointing to main class
- File propertiesFile = new File(getOutputFolder(), "winrun4j.properties");
- Properties properties = new Properties();
- properties.setProperty("main.class", mainClass);
- properties.store(new FileOutputStream(propertiesFile), "WinRun4J Helper Launcher Properties");
-
- // copies winrun4j properties to launcher jar
- JarUtils.addFileToJar(winrun4jJar, propertiesFile);
-
+ // generates ini file
+ File genericIni = new File(getOutputFolder(), "app.ini");
+ VelocityUtils.render("windows/ini.vtl", genericIni, packager);
+ Logger.info("INI file generated in " + genericIni.getAbsolutePath() + "!");
+
// copies ini file to app folder
File iniFile = new File(appFolder, name + ".ini");
FileUtils.copyFileToFile(genericIni, iniFile);
- // signs generated exe file
- sign(getGenericExe(), packager);
-
// copies exe file to app folder with apps name
FileUtils.copyFileToFile(getGenericExe(), executable);
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateAppImage.java b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateAppImage.java
index a076215e..5450e4b1 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateAppImage.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateAppImage.java
@@ -1,15 +1,14 @@
package io.github.fvarrui.javapackager.packagers;
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.commons.lang3.SystemUtils;
-
import io.github.fvarrui.javapackager.model.Platform;
import io.github.fvarrui.javapackager.utils.CommandUtils;
import io.github.fvarrui.javapackager.utils.FileUtils;
import io.github.fvarrui.javapackager.utils.Logger;
import io.github.fvarrui.javapackager.utils.VelocityUtils;
+import org.apache.commons.lang3.SystemUtils;
+
+import java.io.File;
+import java.io.IOException;
public class GenerateAppImage extends ArtifactGenerator {
@@ -97,7 +96,7 @@ private File getAppImageTool(LinuxPackager packager) throws Exception {
try {
FileUtils.downloadFromUrl(imageToolUrl, appImageTool);
} catch (IOException e) {
- throw new Exception(imageToolUrl + "not found! ... Unsupported OS architecture " + getOSArch() + "?");
+ 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);
}
appImageTool.setExecutable(true);
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateDeb.java b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateDeb.java
index ec9376e1..5003d74d 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateDeb.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateDeb.java
@@ -22,7 +22,7 @@
*/
public class GenerateDeb extends ArtifactGenerator {
- private Console console;
+ private final Console console;
public GenerateDeb() {
super("DEB package");
@@ -64,6 +64,8 @@ protected File doApply(LinuxPackager packager) throws Exception {
File executable = packager.getExecutable();
File javaFile = new File(appFolder, jreDirectoryName + "/bin/java");
File mimeXmlFile = packager.getMimeXmlFile();
+ String installationPath = packager.getLinuxConfig().getInstallationPath();
+ String appPath = installationPath + "/" + name;
// generates desktop file from velocity template
File desktopFile = new File(assetsFolder, name + ".desktop");
@@ -80,14 +82,14 @@ protected File doApply(LinuxPackager packager) throws Exception {
// create data producers collections
- List conffilesProducers = new ArrayList<>();
+ List confFilesProducers = new ArrayList<>();
List dataProducers = new ArrayList<>();
// builds app folder data producer, except executable file and jre/bin/java
Mapper appFolderMapper = new Mapper();
appFolderMapper.setType("perm");
- appFolderMapper.setPrefix("/opt/" + name);
+ appFolderMapper.setPrefix(appPath);
appFolderMapper.setFileMode("644");
Data appFolderData = new Data();
@@ -102,12 +104,12 @@ protected File doApply(LinuxPackager packager) throws Exception {
Mapper executableMapper = new Mapper();
executableMapper.setType("perm");
- executableMapper.setPrefix("/opt/" + name);
+ executableMapper.setPrefix(appPath);
executableMapper.setFileMode("755");
Data executableData = new Data();
executableData.setType("file");
- executableData.setSrc(new File(appFolder.getAbsolutePath() + "/" + name));
+ executableData.setSrc(executable);
executableData.addMapper(executableMapper);
dataProducers.add(executableData);
@@ -150,7 +152,7 @@ protected File doApply(LinuxPackager packager) throws Exception {
Mapper javaBinaryMapper = new Mapper();
javaBinaryMapper.setType("perm");
javaBinaryMapper.setFileMode("755");
- javaBinaryMapper.setPrefix("/opt/" + name + "/" + jreDirectoryName + "/bin");
+ javaBinaryMapper.setPrefix(appPath + "/" + jreDirectoryName + "/bin");
Data javaBinaryData = new Data();
javaBinaryData.setType("file");
@@ -168,7 +170,7 @@ protected File doApply(LinuxPackager packager) throws Exception {
Mapper javaSpawnHelperMapper = new Mapper();
javaSpawnHelperMapper.setType("perm");
javaSpawnHelperMapper.setFileMode("755");
- javaSpawnHelperMapper.setPrefix("/opt/" + name + "/" + jreDirectoryName + "/lib");
+ javaSpawnHelperMapper.setPrefix(appPath + "/" + jreDirectoryName + "/lib");
Data javaSpawnHelperData = new Data();
javaSpawnHelperData.setType("file");
@@ -182,13 +184,13 @@ protected File doApply(LinuxPackager packager) throws Exception {
// symbolic link in /usr/local/bin to app binary data producer
- DataProducer linkData = createLink("/usr/local/bin/" + name, "/opt/" + name + "/" + name);
+ DataProducer linkData = createLink("/usr/local/bin/" + executable.getName(), appPath + "/" + executable.getName());
dataProducers.add(linkData);
// builds deb file
- DebMaker debMaker = new DebMaker(console, dataProducers, conffilesProducers);
+ DebMaker debMaker = new DebMaker(console, dataProducers, confFilesProducers);
debMaker.setDeb(debFile);
debMaker.setControl(controlFile.getParentFile());
debMaker.setCompression("gzip");
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateDmg.java b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateDmg.java
index e0b2d610..c87db78d 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateDmg.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateDmg.java
@@ -5,6 +5,7 @@
import java.io.File;
import java.util.Arrays;
+import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
@@ -86,7 +87,7 @@ protected File doApply(MacPackager packager) throws Exception {
// creates image
Logger.info("Creating image: " + tempDmgFile.getAbsolutePath());
String osArchitecture = System.getProperty("os.arch");
- boolean isAarch64 = osArchitecture.toLowerCase().equals("aarch64");
+ boolean isAarch64 = osArchitecture.equalsIgnoreCase("aarch64");
String fileSystem = isAarch64 ? "APFS" : "HFS+";
Logger.warn(osArchitecture + " architecture detected. Using " + fileSystem + " filesystem");
execute("hdiutil", "create", "-srcfolder", appFolder, "-volname", volumeName, "-ov", "-fs", fileSystem, "-format", "UDRW", tempDmgFile);
@@ -99,13 +100,12 @@ protected File doApply(MacPackager packager) throws Exception {
// mounts image
Logger.info("Mounting image: " + tempDmgFile.getAbsolutePath());
String result = execute("hdiutil", "attach", "-readwrite", "-noverify", "-noautoopen", tempDmgFile);
- String deviceName = Arrays.asList(result.split("\n"))
- .stream()
- .filter(s -> s.contains(mountFolder.getAbsolutePath()))
- .map(s -> StringUtils.normalizeSpace(s))
- .map(s -> s.split(" ")[0])
- .findFirst().get();
- Logger.info("- Device name: " + deviceName);
+ Optional optDeviceName = Arrays.stream(result.split("\n"))
+ .filter(s -> s.contains(mountFolder.getAbsolutePath()))
+ .map(StringUtils::normalizeSpace)
+ .map(s -> s.split(" ")[0])
+ .findFirst();
+ optDeviceName.ifPresent(deviceName -> Logger.info("- Device name: " + deviceName));
// pause to prevent occasional "Can't get disk" (-1728) issues
// https://github.com/seltzered/create-dmg/commit/5fe7802917bb85b40c0630b026d33e421db914ea
@@ -134,7 +134,11 @@ protected File doApply(MacPackager packager) throws Exception {
if (!isAarch64) {
// makes the top window open itself on mount:
Logger.info("Blessing ...");
- execute("bless", "--folder", mountFolder, "--openfolder", mountFolder);
+ try {
+ execute("bless", "--folder", mountFolder, "--openfolder", mountFolder); }
+ catch (Exception e){
+ Logger.warn("Error blessing " + mountFolder + " due to: " + e.getMessage());
+ }
}
// tells the volume that it has a special file attribute
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsi.java b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsi.java
index 10f3e9ca..373a3ee8 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsi.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsi.java
@@ -8,12 +8,13 @@
import io.github.fvarrui.javapackager.utils.Logger;
import io.github.fvarrui.javapackager.utils.VelocityUtils;
import io.github.fvarrui.javapackager.utils.XMLUtils;
+import net.jsign.WindowsSigner;
/**
- * Creates a MSI file including all app folder's content only for
+ * Creates an MSI file including all app folder's content only for
* Windows so app could be easily distributed
*/
-public class GenerateMsi extends WindowsArtifactGenerator {
+public class GenerateMsi extends ArtifactGenerator {
public GenerateMsi() {
super("MSI installer");
@@ -50,7 +51,7 @@ protected File doApply(WindowsPackager packager) throws Exception {
VelocityUtils.render("windows/wxs.vtl", wxsFile, packager);
Logger.info("WXS file generated in " + wxsFile + "!");
- // pretiffy wxs
+ // prettify wxs
XMLUtils.prettify(wxsFile);
// candle wxs file
@@ -62,7 +63,7 @@ protected File doApply(WindowsPackager packager) throws Exception {
// lighting wxs file
Logger.info("Linking file " + wixobjFile);
File msiFile = new File(outputDirectory, name + "_" + version + ".msi");
- execute("light", "-spdb", "-out", msiFile, wixobjFile);
+ execute("light", "-sw1076", "-spdb", "-out", msiFile, wixobjFile);
// setup file
if (!msiFile.exists()) {
@@ -70,8 +71,8 @@ protected File doApply(WindowsPackager packager) throws Exception {
}
// sign installer
- sign(msiFile, packager);
-
+ WindowsSigner.sign(msiFile, packager.getDisplayName(), packager.getUrl(), packager.getWinConfig().getSigning());
+
return msiFile;
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsm.java b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsm.java
index 3aad9dc4..06b5a97b 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsm.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateMsm.java
@@ -9,10 +9,10 @@
import io.github.fvarrui.javapackager.utils.XMLUtils;
/**
- * Creates a MSI file including all app folder's content only for Windows so app
+ * Creates an MSI file including all app folder's content only for Windows so app
* could be easily distributed
*/
-public class GenerateMsm extends WindowsArtifactGenerator {
+public class GenerateMsm extends ArtifactGenerator {
public GenerateMsm() {
super("MSI merge module");
@@ -50,7 +50,7 @@ protected File doApply(WindowsPackager packager) throws Exception {
VelocityUtils.render("windows/msm.wxs.vtl", wxsFile, packager);
Logger.info("WXS file generated in " + wxsFile + "!");
- // pretiffy wxs
+ // prettify wxs
XMLUtils.prettify(wxsFile);
// candle wxs file
@@ -62,7 +62,7 @@ protected File doApply(WindowsPackager packager) throws Exception {
// lighting wxs file
Logger.info("Linking file " + wixobjFile);
File msmFile = new File(outputDirectory, name + "_" + version + ".msm");
- CommandUtils.execute("light", "-spdb", "-out", msmFile, wixobjFile);
+ CommandUtils.execute("light", "-sw1076", "-spdb", "-out", msmFile, wixobjFile);
// setup file
if (!msmFile.exists()) {
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateRpm.java b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateRpm.java
index 7a2f473b..e063a645 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateRpm.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateRpm.java
@@ -5,6 +5,7 @@
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import org.redline_rpm.Builder;
import org.redline_rpm.header.Architecture;
@@ -42,13 +43,15 @@ protected File doApply(LinuxPackager packager) throws Exception {
File executable = packager.getExecutable();
File assetsFolder = packager.getAssetsFolder();
String jreDirectoryName = packager.getJreDirectoryName();
- Architecture arch = Architecture.valueOf(packager.getArch().getRpm());
+ Architecture arch = packager.getArch().toRpmArchitecture();
File mimeXmlFile = packager.getMimeXmlFile();
-
+ String installationPath = packager.getLinuxConfig().getInstallationPath();
+ String appPath = installationPath + "/" + name;
+
// generates desktop file from velocity template
File desktopFile = new File(assetsFolder, name + ".desktop");
VelocityUtils.render("linux/desktop.vtl", desktopFile, packager);
- Logger.info("Rendering desktop file to " + desktopFile.getAbsolutePath());
+ Logger.info("Desktop file rendered in " + desktopFile.getAbsolutePath());
// copies desktop file to app
FileUtils.copyFileToFolder(desktopFile, appFolder);
@@ -60,7 +63,7 @@ protected File doApply(LinuxPackager packager) throws Exception {
builder.setPackage(name, version, "1");
builder.setPackager(organizationName);
builder.setDescription(description);
- builder.setPrefixes("opt");
+ builder.setPrefixes(installationPath);
// list of files which needs execution permissions
List executionPermissions = new ArrayList<>();
@@ -69,25 +72,28 @@ protected File doApply(LinuxPackager packager) throws Exception {
executionPermissions.add(new File(appFolder, jreDirectoryName + "/lib/jspawnhelper"));
// add all app files
- addDirectoryTree(builder, "/opt", appFolder, executionPermissions);
+ addDirectory(builder, installationPath, appFolder, executionPermissions);
// link to desktop file
- builder.addLink("/usr/share/applications/" + desktopFile.getName(), "/opt/" + name + "/" + desktopFile.getName());
+ addLink(builder, "/usr/share/applications/" + desktopFile.getName(), appPath + "/" + desktopFile.getName());
// copy and link to mime.xml file
if (mimeXmlFile != null) {
FileUtils.copyFileToFolder(mimeXmlFile, appFolder);
- builder.addLink("/usr/share/mime/packages/" + mimeXmlFile.getName(), "/opt/" + name + "/" + mimeXmlFile.getName());
+ addLink(builder, "/usr/share/mime/packages/" + mimeXmlFile.getName(), appPath + "/" + mimeXmlFile.getName());
}
// link to binary
- builder.addLink("/usr/local/bin/" + executable.getName(), "/opt/" + name + "/" + executable.getName());
+ addLink(builder, "/usr/local/bin/" + executable.getName(), appPath + "/" + executable.getName());
+ // add all app files
+ addDirectory(builder, installationPath, appFolder, executionPermissions);
+
// build RPM file
builder.build(outputDirectory);
- // renames genewrated RPM file if created
- String suffix = "-1." + arch.name().toLowerCase() + ".rpm";
+ // renames generated RPM file if created
+ String suffix = "-1." + arch + ".rpm";
File originalRpm = new File(outputDirectory, name + "-" + version + suffix);
File rpm = null;
if (originalRpm.exists()) {
@@ -98,15 +104,27 @@ protected File doApply(LinuxPackager packager) throws Exception {
return rpm;
}
+
+ private void addLink(Builder builder, String path, String target) throws NoSuchAlgorithmException, IOException {
+ Logger.info("Adding link '" + path + "' to RPM builder targeting '" + target + "'");
+ builder.addLink(path, target);
+ }
+
+ private void addFile(Builder builder, String rootPath, File file, int mode) throws NoSuchAlgorithmException, IOException {
+ String filePath = rootPath + "/" + file.getName();
+ Logger.info("Adding file '" + file + "' to RPM builder as '" + filePath + "'");
+ builder.addFile(filePath, file, mode);
+ }
- private void addDirectoryTree(Builder builder, String parentPath, File root, List executionPermissions) throws NoSuchAlgorithmException, IOException {
- String rootPath = parentPath + "/" + root.getName();
- builder.addDirectory(rootPath);
- for (File f : root.listFiles()) {
+ private void addDirectory(Builder builder, String parentPath, File directory, List executionPermissions) throws NoSuchAlgorithmException, IOException {
+ String dirPath = parentPath + "/" + directory.getName();
+ Logger.info("Adding directory '" + directory + "' to RPM builder as '" + dirPath + "'");
+ builder.addDirectory(dirPath);
+ for (File f : Objects.requireNonNull(directory.listFiles())) {
if (f.isDirectory())
- addDirectoryTree(builder, parentPath + "/" + root.getName(), f, executionPermissions);
+ addDirectory(builder, dirPath, f, executionPermissions);
else {
- builder.addFile(rootPath + "/" + f.getName(), f, executionPermissions.contains(f) ? 0755 : 0644);
+ addFile(builder, dirPath, f, executionPermissions.contains(f) ? 0755 : 0644);
}
}
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateSetup.java b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateSetup.java
index 801b7f91..d78dca9d 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateSetup.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/GenerateSetup.java
@@ -2,20 +2,18 @@
import java.io.File;
-import org.apache.commons.lang3.StringUtils;
-
import io.github.fvarrui.javapackager.model.Platform;
-import io.github.fvarrui.javapackager.model.Registry;
import io.github.fvarrui.javapackager.utils.CommandUtils;
import io.github.fvarrui.javapackager.utils.FileUtils;
import io.github.fvarrui.javapackager.utils.Logger;
import io.github.fvarrui.javapackager.utils.VelocityUtils;
+import net.jsign.WindowsSigner;
/**
* Creates a Setup file including all app folder's content only for
* Windows so app could be easily distributed
*/
-public class GenerateSetup extends WindowsArtifactGenerator {
+public class GenerateSetup extends ArtifactGenerator {
public GenerateSetup() {
super("Setup installer");
@@ -44,21 +42,15 @@ protected File doApply(WindowsPackager packager) throws Exception {
String name = packager.getName();
File outputDirectory = packager.getOutputDirectory();
String version = packager.getVersion();
- Registry registry = packager.getWinConfig().getRegistry();
-
- // checks if registry entries' names are not empy
- if (registry.getEntries().stream().anyMatch(e -> StringUtils.isBlank(e.getKey()) || StringUtils.isBlank(e.getValueName()))) {
- throw new Exception("One or more registry entries have no key and/or value name");
- }
// copies ico file to assets folder
FileUtils.copyFileToFolder(iconFile, assetsFolder);
// generates iss file from velocity template
File issFile = new File(assetsFolder, name + ".iss");
- VelocityUtils.render("windows/iss.vtl", issFile, packager, true);
+ VelocityUtils.render("windows/iss.vtl", issFile, packager);
- // generates windows installer with inno setup command line compiler
+ // generates Windows installer with inno setup command line compiler
CommandUtils.execute("iscc", "/O" + outputDirectory.getAbsolutePath(), "/F" + name + "_" + version, issFile);
// setup file
@@ -68,8 +60,8 @@ protected File doApply(WindowsPackager packager) throws Exception {
}
// sign installer
- sign(setupFile, packager);
-
+ WindowsSigner.sign(setupFile, packager.getDisplayName(), packager.getUrl(), packager.getWinConfig().getSigning());
+
return setupFile;
}
diff --git a/src/main/java/io/github/fvarrui/javapackager/packagers/MacPackager.java b/src/main/java/io/github/fvarrui/javapackager/packagers/MacPackager.java
index 5173f4f1..05cf90d6 100644
--- a/src/main/java/io/github/fvarrui/javapackager/packagers/MacPackager.java
+++ b/src/main/java/io/github/fvarrui/javapackager/packagers/MacPackager.java
@@ -9,11 +9,19 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
/**
* Packager for MacOS
@@ -25,6 +33,12 @@ public class MacPackager extends Packager {
private File resourcesFolder;
private File javaFolder;
private File macOSFolder;
+ private File jreBundleFolder;
+
+ public MacPackager() {
+ super();
+ platform(Platform.mac);
+ }
public File getAppFile() {
return appFile;
@@ -73,7 +87,8 @@ protected void doCreateAppStructure() throws Exception {
// sets common folders
this.executableDestinationFolder = macOSFolder;
this.jarFileDestinationFolder = javaFolder;
- this.jreDestinationFolder = new File(contentsFolder, "PlugIns/" + jreDirectoryName + "/Contents/Home");
+ this.jreBundleFolder = new File(contentsFolder, "PlugIns/" + jreDirectoryName + ".jre");
+ this.jreDestinationFolder = new File(jreBundleFolder, "Contents/Home");
this.resourcesDestinationFolder = resourcesFolder;
}
@@ -83,6 +98,9 @@ protected void doCreateAppStructure() throws Exception {
*/
@Override
public File doCreateApp() throws Exception {
+ if(bundleJre) {
+ processRuntimeInfoPlistFile();
+ }
// copies jarfile to Java folder
FileUtils.copyFileToFolder(jarFile, javaFolder);
@@ -97,6 +115,8 @@ public File doCreateApp() throws Exception {
codesign();
+ notarize();
+
return appFile;
}
@@ -157,6 +177,21 @@ private void processInfoPlistFile() throws Exception {
Logger.info("Info.plist file created in " + infoPlistFile.getAbsolutePath());
}
+ /**
+ * Creates and writes the Info.plist inside the JRE if no custom file is specified.
+ * @throws Exception if anything goes wrong
+ */
+ private void processRuntimeInfoPlistFile() throws Exception {
+ File infoPlistFile = new File(jreBundleFolder, "Contents/Info.plist");
+ if(macConfig.getCustomRuntimeInfoPlist() != null && macConfig.getCustomRuntimeInfoPlist().isFile() && macConfig.getCustomRuntimeInfoPlist().canRead()){
+ FileUtils.copyFileToFile(macConfig.getCustomRuntimeInfoPlist(), infoPlistFile);
+ } else {
+ VelocityUtils.render("mac/RuntimeInfo.plist.vtl", infoPlistFile, this);
+ XMLUtils.prettify(infoPlistFile);
+ }
+ Logger.info("RuntimeInfo.plist file created in " + infoPlistFile.getAbsolutePath());
+ }
+
private void codesign() throws Exception {
if (!Platform.mac.isCurrentPlatform()) {
Logger.warn("Generated app could not be signed due to current platform is " + Platform.getCurrentPlatform());
@@ -167,6 +202,18 @@ private void codesign() throws Exception {
}
}
+ private void notarize() throws Exception {
+ if (!Platform.mac.isCurrentPlatform()) {
+ Logger.warn("Generated app could not be notarized due to current platform is " + Platform.getCurrentPlatform());
+ } else if (!getMacConfig().isCodesignApp()) {
+ Logger.warn("App codesigning disabled. Cannot notarize unsigned app");
+ } else if (!getMacConfig().isNotarizeApp()) {
+ Logger.warn("App notarization disabled");
+ } else {
+ notarize(this.macConfig.getKeyChainProfile(), this.appFile);
+ }
+ }
+
private void processProvisionProfileFile() throws Exception {
if (macConfig.getProvisionProfile() != null && macConfig.getProvisionProfile().isFile() && macConfig.getProvisionProfile().canRead()) {
// file name must be 'embedded.provisionprofile'
@@ -195,13 +242,13 @@ private File preparePrecompiledStartupStub() throws Exception {
private void codesign(String developerId, File entitlements, File appFile) throws Exception {
- prepareEntitlementFile(entitlements);
+ entitlements = prepareEntitlementFile(entitlements);
- manualDeepSign(appFile, developerId, entitlements);
+ signAppBundle(appFile, developerId, entitlements);
}
- private void prepareEntitlementFile(File entitlements) throws Exception {
+ private File prepareEntitlementFile(File entitlements) throws Exception {
// if entitlements.plist file not specified, use a default one
if (entitlements == null) {
Logger.warn("Entitlements file not specified. Using defaults!");
@@ -210,45 +257,58 @@ private void prepareEntitlementFile(File entitlements) throws Exception {
} else if (!entitlements.exists()) {
throw new Exception("Entitlements file doesn't exist: " + entitlements);
}
+ return entitlements;
}
- private void manualDeepSign(File appFolder, String developerCertificateName, File entitlements) throws IOException, CommandLineException {
-
- // codesign each file in app
- List