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 -[![Maven Central](http://img.shields.io/maven-central/v/io.github.fvarrui/javapackager)](https://search.maven.org/artifact/io.github.fvarrui/javapackager) +[![Maven Central](http://img.shields.io/maven-central/v/io.github.fvarrui/javapackager)](https://central.sonatype.com/search?smo=true&q=a%3Ajavapackager+g%3Aio.github.fvarrui) [![GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-%250778B9.svg)](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