├── .gitignore ├── maven-plugin ├── src │ ├── it │ │ ├── 01-minimal-setup │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── minimalsetup │ │ │ │ │ └── Main.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 08-create-keystore │ │ │ ├── invoker.properties │ │ │ ├── verify.bsh │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── minimalsetup │ │ │ │ │ └── Main.java │ │ │ └── pom.xml │ │ ├── 09-sign-minimal-setup │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── minimalsetup │ │ │ │ │ └── Main.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 04-simple-spring-boot-setup │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── simplespringbootsetup │ │ │ │ │ └── MainEntrypoint.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 02-minimal-setup-custom-main-class │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── minimalsetupcustommainclass │ │ │ │ │ ├── Main.java │ │ │ │ │ └── SecondMain.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 10-additional-java-app-resources │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ ├── distbundle │ │ │ │ │ └── java-app │ │ │ │ │ │ └── resources │ │ │ │ │ │ └── README.md │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── minimalsetup │ │ │ │ │ └── Main.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 05-custom-source-artifact-classifier │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── customsourceartifactclassifier │ │ │ │ │ └── MainEntrypoint.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 11-zip-and-attach-as-project-artifact │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ ├── distbundle │ │ │ │ │ └── java-app │ │ │ │ │ │ └── resources │ │ │ │ │ │ └── README.md │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── minimalsetup │ │ │ │ │ └── Main.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 03-minimal-setup-without-prior-main-class │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── minimalsetupwithoutpriormainclass │ │ │ │ │ └── Main.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 13-generate-classpath-using-lib-folder-content │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── minimalsetup │ │ │ │ │ └── Main.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 07-zipped-java-app-using-spring-boot-without-fatjar │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── example7 │ │ │ │ │ └── MainEntrypoint.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 12-zip-and-attach-as-project-artifact-with-target-classifier │ │ │ ├── invoker.properties │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ ├── distbundle │ │ │ │ │ └── java-app │ │ │ │ │ │ └── resources │ │ │ │ │ │ └── README.md │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── minimalsetup │ │ │ │ │ └── Main.java │ │ │ ├── verify.bsh │ │ │ └── pom.xml │ │ ├── 06-simple-javafx-with-spring-boot-setup │ │ │ ├── invoker.properties │ │ │ ├── verify.bsh │ │ │ ├── src │ │ │ │ └── main │ │ │ │ │ └── java │ │ │ │ │ └── de │ │ │ │ │ └── dynamicfiles │ │ │ │ │ └── projects │ │ │ │ │ └── maven │ │ │ │ │ └── distributionbundleplugin │ │ │ │ │ └── example │ │ │ │ │ └── simplejavafxwithspringbootsetup │ │ │ │ │ └── MainEntrypoint.java │ │ │ └── pom.xml │ │ └── settings.xml │ └── main │ │ └── java │ │ └── de │ │ └── dynamicfiles │ │ └── projects │ │ └── maven │ │ └── distributionbundleplugin │ │ ├── mojo │ │ ├── CreateNativeAppInstaller.java │ │ ├── CreateTempKeystore.java │ │ └── CreateNativeAppBundle.java │ │ └── InternalUtils.java ├── license.header └── pom.xml ├── bundler-implementations ├── native-app-windows-x64 │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ ├── META-INF │ │ │ │ └── services │ │ │ │ │ └── de.dynamicfiles.projects.maven.distributionbundleplugin.spi.NativeAppBundler │ │ │ └── de │ │ │ │ └── dynamicfiles │ │ │ │ └── projects │ │ │ │ └── maven │ │ │ │ └── distributionbundleplugin │ │ │ │ └── bundler │ │ │ │ └── nativeapp │ │ │ │ └── windows │ │ │ │ └── x64 │ │ │ │ ├── configurationModuleTemplate.ini │ │ │ │ └── configurationTemplate.ini │ │ │ └── java │ │ │ └── de │ │ │ └── dynamicfiles │ │ │ └── projects │ │ │ └── maven │ │ │ └── distributionbundleplugin │ │ │ └── bundler │ │ │ └── nativeapp │ │ │ └── windows │ │ │ └── x64 │ │ │ ├── InternalParameterEnum.java │ │ │ └── NativeAppBundlerUsingResourcesFromOracleJDK.java │ └── pom.xml └── pom.xml ├── bundler-spi ├── src │ └── main │ │ └── java │ │ └── de │ │ └── dynamicfiles │ │ └── projects │ │ └── maven │ │ └── distributionbundleplugin │ │ ├── api │ │ ├── OS.java │ │ ├── NativeInstallerOptions.java │ │ ├── SharedInternalTools.java │ │ ├── NativeLauncher.java │ │ └── NativeAppOptions.java │ │ └── spi │ │ ├── NativeInstallerBundle.java │ │ └── NativeAppBundler.java └── pom.xml ├── appveyor.yml ├── CONTRIBUTING.md ├── .travis.yml ├── pom.xml ├── README.md └── LICENSE.md /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ -------------------------------------------------------------------------------- /maven-plugin/src/it/01-minimal-setup/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/08-create-keystore/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/09-sign-minimal-setup/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/04-simple-spring-boot-setup/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/02-minimal-setup-custom-main-class/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/10-additional-java-app-resources/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/05-custom-source-artifact-classifier/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/11-zip-and-attach-as-project-artifact/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean install 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/03-minimal-setup-without-prior-main-class/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/13-generate-classpath-using-lib-folder-content/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/07-zipped-java-app-using-spring-boot-without-fatjar/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/12-zip-and-attach-as-project-artifact-with-target-classifier/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean install 2 | -------------------------------------------------------------------------------- /maven-plugin/src/it/06-simple-javafx-with-spring-boot-setup/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean package 2 | invoker.java.version = !11+ 3 | -------------------------------------------------------------------------------- /maven-plugin/src/it/10-additional-java-app-resources/src/main/distbundle/java-app/resources/README.md: -------------------------------------------------------------------------------- 1 | some kind of useful stuff, just here for showing how works -------------------------------------------------------------------------------- /maven-plugin/src/it/11-zip-and-attach-as-project-artifact/src/main/distbundle/java-app/resources/README.md: -------------------------------------------------------------------------------- 1 | some kind of useful stuff, just here for showing how works -------------------------------------------------------------------------------- /maven-plugin/src/it/12-zip-and-attach-as-project-artifact-with-target-classifier/src/main/distbundle/java-app/resources/README.md: -------------------------------------------------------------------------------- 1 | some kind of useful stuff, just here for showing how works -------------------------------------------------------------------------------- /maven-plugin/src/it/08-create-keystore/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File keystoreFile = new File( basedir, "src/main/distbundle/java-app/keystore.pkcs12" ); 4 | if( !keystoreFile.exists() ){ 5 | throw new Exception( "there should be a keystore-file!"); 6 | } -------------------------------------------------------------------------------- /bundler-implementations/native-app-windows-x64/src/main/resources/META-INF/services/de.dynamicfiles.projects.maven.distributionbundleplugin.spi.NativeAppBundler: -------------------------------------------------------------------------------- 1 | de.dynamicfiles.projects.maven.distributionbundleplugin.bundler.nativeapp.windows.x64.NativeAppBundlerUsingResourcesFromOracleJDK -------------------------------------------------------------------------------- /maven-plugin/src/it/01-minimal-setup/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetup/Main.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /maven-plugin/src/it/08-create-keystore/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetup/Main.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /maven-plugin/src/it/09-sign-minimal-setup/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetup/Main.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /maven-plugin/src/it/10-additional-java-app-resources/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetup/Main.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /maven-plugin/src/it/11-zip-and-attach-as-project-artifact/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetup/Main.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /maven-plugin/src/it/13-generate-classpath-using-lib-folder-content/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetup/Main.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /maven-plugin/src/it/12-zip-and-attach-as-project-artifact-with-target-classifier/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetup/Main.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /maven-plugin/src/it/02-minimal-setup-custom-main-class/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetupcustommainclass/Main.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetupcustommainclass; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /maven-plugin/src/it/03-minimal-setup-without-prior-main-class/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetupwithoutpriormainclass/Main.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetupwithoutpriormainclass; 2 | 3 | public class Main { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /maven-plugin/src/it/02-minimal-setup-custom-main-class/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/minimalsetupcustommainclass/SecondMain.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetupcustommainclass; 2 | 3 | public class SecondMain { 4 | 5 | public static void main(String[] args) { 6 | System.out.println("Hello World from second main class."); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /bundler-implementations/native-app-windows-x64/src/main/resources/de/dynamicfiles/projects/maven/distributionbundleplugin/bundler/nativeapp/windows/x64/configurationModuleTemplate.ini: -------------------------------------------------------------------------------- 1 | [Application] 2 | app.name={{template_app_name}} 3 | app.version={{template_app_version}} 4 | app.preferences.id={{template_app_preferences_id}} 5 | app.runtime={{template_app_runtime}} 6 | app.identifier={{template_app_identifier}} 7 | app.classpath={{template_app_classpath}} 8 | 9 | app.mainmodule={{template_app_mainmodule}} 10 | 11 | [JVMOptions] 12 | 13 | [JVMUserOptions] 14 | 15 | [ArgOptions] 16 | -------------------------------------------------------------------------------- /bundler-implementations/native-app-windows-x64/src/main/resources/de/dynamicfiles/projects/maven/distributionbundleplugin/bundler/nativeapp/windows/x64/configurationTemplate.ini: -------------------------------------------------------------------------------- 1 | [Application] 2 | app.name={{template_app_name}} 3 | app.version={{template_app_version}} 4 | app.preferences.id={{template_app_preferences_id}} 5 | app.runtime={{template_app_runtime}} 6 | app.identifier={{template_app_identifier}} 7 | app.classpath={{template_app_classpath}} 8 | 9 | app.mainclass={{template_app_mainclass}} 10 | app.mainjar={{template_app_mainjar}} 11 | 12 | [JVMOptions] 13 | 14 | [JVMUserOptions] 15 | 16 | [ArgOptions] 17 | -------------------------------------------------------------------------------- /maven-plugin/license.header: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ -------------------------------------------------------------------------------- /maven-plugin/src/it/01-minimal-setup/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "minimal-setup-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | 19 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 20 | if( !executionPropertiesFile.exists() ){ 21 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 22 | } 23 | -------------------------------------------------------------------------------- /maven-plugin/src/it/04-simple-spring-boot-setup/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/simplespringbootsetup/MainEntrypoint.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.simplespringbootsetup; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | @Controller 10 | @EnableAutoConfiguration 11 | public class MainEntrypoint { 12 | 13 | @RequestMapping("/") 14 | @ResponseBody 15 | String home() { 16 | return "Hello World!"; 17 | } 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(MainEntrypoint.class, args); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /maven-plugin/src/it/07-zipped-java-app-using-spring-boot-without-fatjar/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/example7/MainEntrypoint.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.example7; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | @Controller 10 | @EnableAutoConfiguration 11 | public class MainEntrypoint { 12 | 13 | @RequestMapping("/") 14 | @ResponseBody 15 | String home() { 16 | return "Hello World!"; 17 | } 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(MainEntrypoint.class, args); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /bundler-spi/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/api/OS.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.api; 17 | 18 | /** 19 | * 20 | * @author Danny Althoff 21 | */ 22 | public enum OS { 23 | WINDOWS, LINUX, MAC 24 | } 25 | -------------------------------------------------------------------------------- /maven-plugin/src/it/02-minimal-setup-custom-main-class/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "minimal-setup-custom-main-class-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | 19 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 20 | if( !executionPropertiesFile.exists() ){ 21 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 22 | } 23 | -------------------------------------------------------------------------------- /maven-plugin/src/it/03-minimal-setup-without-prior-main-class/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "minimal-setup-without-prior-main-class-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | 19 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 20 | if( !executionPropertiesFile.exists() ){ 21 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 22 | } 23 | -------------------------------------------------------------------------------- /maven-plugin/src/it/05-custom-source-artifact-classifier/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/customsourceartifactclassifier/MainEntrypoint.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.customsourceartifactclassifier; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | @Controller 10 | @EnableAutoConfiguration 11 | public class MainEntrypoint { 12 | 13 | @RequestMapping("/") 14 | @ResponseBody 15 | String home() { 16 | return "Hello World!"; 17 | } 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(MainEntrypoint.class, args); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /bundler-spi/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/api/NativeInstallerOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.api; 17 | 18 | /** 19 | * 20 | * @author Danny Althoff 21 | */ 22 | public class NativeInstallerOptions { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /maven-plugin/src/it/13-generate-classpath-using-lib-folder-content/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "minimal-setup-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | File javaAppLibFolder = new File( javaAppFolder, "lib" ); 19 | if( !javaAppLibFolder.exists() ){ 20 | throw new Exception( "there should be a lib folder!"); 21 | } 22 | 23 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 24 | if( !executionPropertiesFile.exists() ){ 25 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 26 | } 27 | -------------------------------------------------------------------------------- /maven-plugin/src/it/09-sign-minimal-setup/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File keystoreFile = new File( basedir, "src/main/distbundle/java-app/keystore.pkcs12" ); 4 | if( !keystoreFile.exists() ){ 5 | throw new Exception( "there should be a keystore-file!"); 6 | } 7 | 8 | File bundlesFolder = new File( basedir, "target/distbundle" ); 9 | if( !bundlesFolder.exists() ){ 10 | throw new Exception( "there should be a distbundle-folder!"); 11 | } 12 | 13 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 14 | if( !javaAppFolder.exists() ){ 15 | throw new Exception( "there should be a java-app-folder!"); 16 | } 17 | 18 | File javaAppJar = new File( javaAppFolder, "sign-minimal-setup-1.0.jar" ); 19 | if( !javaAppJar.exists() ){ 20 | throw new Exception( "there should be a jar file!"); 21 | } 22 | 23 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 24 | if( !executionPropertiesFile.exists() ){ 25 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 26 | } 27 | -------------------------------------------------------------------------------- /maven-plugin/src/it/04-simple-spring-boot-setup/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "simple-spring-boot-setup-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | // only one jar should exist, no lib-folder or other files 19 | if( javaAppFolder.list().length > 1 ){ 20 | throw new Exception( "only one file is expected to be present!"); 21 | } 22 | 23 | 24 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 25 | if( !executionPropertiesFile.exists() ){ 26 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 27 | } 28 | -------------------------------------------------------------------------------- /maven-plugin/src/it/10-additional-java-app-resources/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "additional-java-app-resources-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | File additionalResourceFile = new File( javaAppFolder, "README.md" ); 18 | if( !additionalResourceFile.exists() ){ 19 | throw new Exception( "there should be a README.md file!"); 20 | } 21 | 22 | 23 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 24 | if( !executionPropertiesFile.exists() ){ 25 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 26 | } 27 | -------------------------------------------------------------------------------- /maven-plugin/src/it/06-simple-javafx-with-spring-boot-setup/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "simple-javafx-with-spring-boot-setup-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | // only one jar should exist, no lib-folder or other files 19 | if( javaAppFolder.list().length > 1 ){ 20 | throw new Exception( "only one file is expected to be present!"); 21 | } 22 | 23 | 24 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 25 | if( !executionPropertiesFile.exists() ){ 26 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 27 | } 28 | -------------------------------------------------------------------------------- /maven-plugin/src/it/05-custom-source-artifact-classifier/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "custom-source-artifact-classifier-1.0-customsourceartifactclassifier.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | // only one jar should exist, no lib-folder or other files 19 | if( javaAppFolder.list().length > 1 ){ 20 | throw new Exception( "only one file is expected to be present!"); 21 | } 22 | 23 | 24 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 25 | if( !executionPropertiesFile.exists() ){ 26 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 27 | } 28 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | ## thanks to https://dzone.com/articles/continuous-integration-windows 2 | ## with some adjustments and exported yaml-settings 3 | 4 | version: '{build}' 5 | os: Windows Server 2012 6 | pull_requests: 7 | do_not_increment_build_number: true 8 | skip_tags: true 9 | install: 10 | - ps: | 11 | Add-Type -AssemblyName System.IO.Compression.FileSystem 12 | if (!(Test-Path -Path "C:\maven" )) { 13 | (new-object System.Net.WebClient).DownloadFile( 14 | 'http://www.us.apache.org/dist/maven/maven-3/3.5.2/binaries/apache-maven-3.5.2-bin.zip', 15 | 'C:\maven-bin.zip' 16 | ) 17 | [System.IO.Compression.ZipFile]::ExtractToDirectory("C:\maven-bin.zip", "C:\maven") 18 | } 19 | $env:Path +=";C:\maven\apache-maven-3.5.2\bin;%JAVA_HOME%\bin" 20 | build_script: 21 | - cmd: mvn clean package --batch-mode -DskipTest 22 | test_script: 23 | - cmd: mvn clean install --batch-mode 24 | 25 | environment: 26 | matrix: 27 | - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 28 | - JAVA_HOME: C:\Program Files (x86)\Java\jdk1.8.0 29 | - JAVA_HOME: C:\Program Files\Java\jdk9 30 | - JAVA_HOME: C:\Program Files\Java\jdk10 31 | 32 | matrix: 33 | fast_finish: true 34 | -------------------------------------------------------------------------------- /maven-plugin/src/it/11-zip-and-attach-as-project-artifact/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "zip-and-attach-as-project-artifact-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 19 | if( !executionPropertiesFile.exists() ){ 20 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 21 | } 22 | 23 | // now check if attached artifact got installed into the repository 24 | File attachedArtifact = new File( basedir, "../../local-repo/de/dynamicfiles/projects/maven/distributionbundleplugin/examples/zip-and-attach-as-project-artifact/1.0/zip-and-attach-as-project-artifact-1.0-java-app-bundle.zip" ); 25 | if( !attachedArtifact.exists() ){ 26 | throw new Exception( "ZIP artifact should have been installed!"); 27 | } 28 | -------------------------------------------------------------------------------- /maven-plugin/src/it/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | it-repo 7 | 8 | true 9 | 10 | 11 | 12 | local.central 13 | @localRepositoryUrl@ 14 | 15 | true 16 | 17 | 18 | true 19 | 20 | 21 | 22 | 23 | 24 | local.central 25 | @localRepositoryUrl@ 26 | 27 | true 28 | 29 | 30 | true 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /maven-plugin/src/it/12-zip-and-attach-as-project-artifact-with-target-classifier/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "zip-and-attach-as-project-artifact-with-target-classifier-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 19 | if( !executionPropertiesFile.exists() ){ 20 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 21 | } 22 | 23 | // now check if attached artifact got installed into the repository 24 | File attachedArtifact = new File( basedir, "../../local-repo/de/dynamicfiles/projects/maven/distributionbundleplugin/examples/zip-and-attach-as-project-artifact-with-target-classifier/1.0/zip-and-attach-as-project-artifact-with-target-classifier-1.0-app.zip" ); 25 | if( !attachedArtifact.exists() ){ 26 | throw new Exception( "ZIP artifact should have been installed!"); 27 | } 28 | -------------------------------------------------------------------------------- /maven-plugin/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/mojo/CreateNativeAppInstaller.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.mojo; 2 | 3 | import java.io.File; 4 | import org.apache.maven.plugin.AbstractMojo; 5 | import org.apache.maven.plugin.MojoExecutionException; 6 | import org.apache.maven.plugin.MojoFailureException; 7 | import org.apache.maven.plugins.annotations.Mojo; 8 | import org.apache.maven.plugins.annotations.Parameter; 9 | import org.apache.maven.project.MavenProject; 10 | 11 | /** 12 | * 13 | * @author FibreFoX 14 | */ 15 | @Mojo(name = "native-installer") 16 | public class CreateNativeAppInstaller extends AbstractMojo { 17 | 18 | @Parameter(defaultValue = "${project}", readonly = true) 19 | private MavenProject project; 20 | 21 | @Parameter(defaultValue = "${project.build.directory}/bundles/native-app") 22 | private File sourceFolder; 23 | 24 | /** 25 | * As the used bundler for creating the native app is not known by this MOJO, the created subfolder must be set here. 26 | */ 27 | @Parameter(required = true) 28 | private String sourceSubFolder; 29 | 30 | @Override 31 | public void execute() throws MojoExecutionException, MojoFailureException { 32 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /maven-plugin/src/it/06-simple-javafx-with-spring-boot-setup/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/example/simplejavafxwithspringbootsetup/MainEntrypoint.java: -------------------------------------------------------------------------------- 1 | package de.dynamicfiles.projects.maven.distributionbundleplugin.example.simplejavafxwithspringbootsetup; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import javafx.application.Application; 10 | import javafx.scene.Scene; 11 | import javafx.scene.control.Label; 12 | import javafx.stage.Stage; 13 | 14 | @Controller 15 | @EnableAutoConfiguration 16 | public class MainEntrypoint extends Application { 17 | 18 | @RequestMapping("/") 19 | @ResponseBody 20 | String home() { 21 | return "Hello World!"; 22 | } 23 | 24 | public static void main(String[] args) { 25 | // some notes: this is not ideal and not optimized ;) 26 | 27 | // first start SpringBoot Application 28 | SpringApplication.run(MainEntrypoint.class, args); 29 | // Then launch the JavaFX-thread (as it is blocking) 30 | Application.launch(args); 31 | } 32 | 33 | @Override 34 | public void start(Stage primaryStage) throws Exception { 35 | primaryStage.setScene(new Scene(new Label("Hello World!"))); 36 | primaryStage.show(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /maven-plugin/src/it/07-zipped-java-app-using-spring-boot-without-fatjar/verify.bsh: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | File bundlesFolder = new File( basedir, "target/distbundle" ); 4 | if( !bundlesFolder.exists() ){ 5 | throw new Exception( "there should be a distbundle-folder!"); 6 | } 7 | 8 | File javaAppFolder = new File( bundlesFolder, "java-app" ); 9 | if( !javaAppFolder.exists() ){ 10 | throw new Exception( "there should be a java-app-folder!"); 11 | } 12 | 13 | File javaAppJar = new File( javaAppFolder, "zipped-java-app-using-spring-boot-without-fatjar-1.0.jar" ); 14 | if( !javaAppJar.exists() ){ 15 | throw new Exception( "there should be a jar file!"); 16 | } 17 | 18 | // normally all libs should reside inside the jar-file (because of spring boot), 19 | // but as we opted out to use that executable-spring-jar-file, we have a lot of dependencies inside 20 | // our lib-folder, makes it possible to not have to worry about compression of libs in BOOT-INF 21 | if( javaAppFolder.list().length > 2 ){ 22 | throw new Exception( "one jar-file and one folder is expected to be present!"); 23 | } 24 | 25 | File executionPropertiesFile = new File( basedir, "target/distbundle.java-app-execution.generate-java-bundle.properties" ); 26 | if( !executionPropertiesFile.exists() ){ 27 | throw new Exception( "there should be a properties file containing all data for that one goal execution!"); 28 | } 29 | 30 | // make sure the ZIP-file got created too 31 | File zippedAppFile = new File( basedir, "target/zipped-java-app-using-spring-boot-without-fatjar-1.0-java-app-bundle.zip" ); 32 | if( !zippedAppFile.exists() ){ 33 | throw new Exception( "the application should get zipped up!"); 34 | } -------------------------------------------------------------------------------- /bundler-spi/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/api/SharedInternalTools.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.api; 17 | 18 | import java.io.File; 19 | import java.io.IOException; 20 | import java.nio.file.Path; 21 | 22 | /** 23 | * 24 | * @author Danny Althoff 25 | */ 26 | public interface SharedInternalTools { 27 | 28 | public boolean copyRecursive(Path sourceFolder, Path targetFolder) throws IOException; 29 | 30 | public boolean deleteRecursive(Path sourceFolder) throws IOException; 31 | 32 | public void pack(final Path folder, final Path zipFilePath) throws IOException; 33 | 34 | public boolean isClassInsideJarFile(String classname, String locationPrefix, File jarFile); 35 | 36 | public boolean isPlatformWindows(); 37 | 38 | public boolean isPlatformLinux(); 39 | 40 | public boolean isPlatformMac(); 41 | 42 | public boolean isLinuxExecutable64bit(Path linuxBinary); 43 | 44 | public boolean isWindowsExecutable64bit(Path windowsBinary); 45 | } 46 | -------------------------------------------------------------------------------- /bundler-implementations/native-app-windows-x64/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/bundler/nativeapp/windows/x64/InternalParameterEnum.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.bundler.nativeapp.windows.x64; 17 | 18 | /** 19 | * 20 | * @author Danny Althoff 21 | */ 22 | public enum InternalParameterEnum { 23 | 24 | /** 25 | * As this bundler contains some magic, while creating the native bundle, it searches for previous 26 | * "java-app" mojo executions to gain some knowledge for the native binary to bootstrap the launch. 27 | */ 28 | USE_JAVAAPP_EXECUTION_ID("useJavaAppExecutionId", Boolean.class); 29 | 30 | private final String parameterName; 31 | private final Class typeToConvertTo; 32 | 33 | private InternalParameterEnum(String parameterName, Class typeToConvertTo) { 34 | this.parameterName = parameterName; 35 | this.typeToConvertTo = typeToConvertTo; 36 | } 37 | 38 | public String getParameterName() { 39 | return parameterName; 40 | } 41 | 42 | public Class getTypeToConvertTo() { 43 | return typeToConvertTo; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Help us to make a better tool 2 | 3 | ## By creating issue-tickets 4 | 5 | When you think you found a bug, please check the issue-tracker at github first, if it isn't already reported. If you are unsure about having the same bug, don't hesitate to create a new issue-ticket, you will be informed about via comment or closing. 6 | 7 | 8 | ## By creating patches, features or pull-requests 9 | 10 | When you managed to find some time in creating a patch or implemented a new feature, please create small pull-requests. Having to merge a pull-request with different fixes or several new features is no easy task and won't be accepted (exceptions of this may occur when having similar small fixes). If new features are added, please create a sample-project inside ```src/it/```-folder, this will be called by ```maven-invoker-plugin``` to ensure all other existing features aren't broken and working as expected. This is also a good documentation to others by showing them how to set their configuration. 11 | 12 | 13 | ## Some words about code-formatters and comments 14 | 15 | I love code-formatters, but until I have strict requirements for this project (I don't have them currently), please **do not** apply your formatter over the whole code, just on your changes should be enough. It shortens the time to check pull-requests for the change you really made (and not making the code look worse than it is). 16 | 17 | If there are some comments you find irritating or confusing (or even being wrong), just create a pull-request to adjust these parts. 18 | 19 | 20 | ## Inform others about this project 21 | 22 | This project lives from the usage by others, show it to some collegues, use it in your spare-time-projects and feel free to spread this project all over the world. Every move to keep this project alive and kicking is very welcome. 23 | 24 | 25 | ## Note about creator/maintainer-feedback 26 | 27 | It may happen, that some comments are getting more rude than expected, this just means that there is a lot of personal commitment is involved. My comments are never for personal insults, just my personal way of pushing my own project. If this hurts your feelings I can assure you that I'm getting hurt feelings myself, but I never see them as a personal attack, so you shouldn't too. 28 | -------------------------------------------------------------------------------- /maven-plugin/src/it/03-minimal-setup-without-prior-main-class/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 6 | minimal-setup-without-prior-main-class 7 | 1.0 8 | jar 9 | 10 | 11 | 12 | Danny Althoff 13 | fibrefox@dynamicfiles.de 14 | https://www.dynamicfiles.de 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.7.0 24 | 25 | 1.8 26 | 1.8 27 | true 28 | 29 | -Xlint:unchecked 30 | 31 | 32 | 33 | 34 | 35 | de.dynamicfiles.projects.maven 36 | distribution-bundle-plugin 37 | @project.version@ 38 | 39 | 40 | generate-java-bundle 41 | package 42 | 43 | java-app 44 | 45 | 46 | 47 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetupwithoutpriormainclass.Main 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /bundler-spi/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/spi/NativeInstallerBundle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.spi; 17 | 18 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.OS; 19 | import java.io.File; 20 | 21 | /** 22 | * 23 | * @author Danny Althoff 24 | */ 25 | public interface NativeInstallerBundle { 26 | 27 | /** 28 | * When having multiple bundlers inside one JAR-file, this is used to identify them. 29 | * 30 | * @return 31 | */ 32 | String getBundlerIdentifier(); 33 | 34 | /** 35 | * Bundlers might depend on locally installed tooling, therefor checking their existence or all requirements being fulfilled 36 | * can be done by this method. 37 | * 38 | * @param jdkPath for checking and required resources or executables, has to be provided JDK 39 | * 40 | * @return 41 | */ 42 | boolean checkRequirements(String jdkPath); 43 | 44 | /** 45 | * 46 | * @param jdkPath 47 | * 48 | * @return the location of the generated installer bundle 49 | */ 50 | File bundleInstaller(String jdkPath); 51 | 52 | /** 53 | * As there is no direct help via maven, this bundler can be enhanced for showing the used additional parameters. 54 | */ 55 | void printHelp(); 56 | 57 | /** 58 | * Returns true when this bundler is being able to run on given build system. Building bundles might be dependend to build system as 59 | * native tooling is used. 60 | * 61 | * @param os 62 | * 63 | * @return true, when this bundler is callable on provided OS, otherwise false 64 | */ 65 | boolean creatableOnBuildsystem(OS os); 66 | 67 | OS getClientOS(); 68 | 69 | /** 70 | * When adding some installer as project-artifact, there has to be some file-extension being specified. 71 | * 72 | * @return file-extension without leading dot and isn't allowed to end with dot 73 | */ 74 | String getInstallerFileExtension(); 75 | } 76 | -------------------------------------------------------------------------------- /bundler-spi/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/api/NativeLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.api; 17 | 18 | import java.io.File; 19 | 20 | /** 21 | * 22 | * @author Danny Althoff 23 | */ 24 | public class NativeLauncher { 25 | 26 | /** 27 | * The filename of the native launcher file (without file extension). 28 | */ 29 | private String filename = null; 30 | 31 | /** 32 | * The file extension of the native launcher file (e.g. ".exe", ".scr", ...). 33 | */ 34 | private String extension = null; 35 | 36 | /** 37 | * The executable native launcher sometimes needs a custom configuration, e.G. some special 38 | * JVM-options or even a different main-class or some special agentlib-configuration. 39 | * TODO: add more documentation e.g. for template and replacement-strings 40 | */ 41 | private String configuration = null; 42 | 43 | /** 44 | * Same as "configuration", but is ment to point to a template-file. Using this parameter overrides the made 45 | * configuration inside "configuration"-parameter. 46 | */ 47 | private File configurationFile = null; 48 | 49 | public String getFilename() { 50 | return filename; 51 | } 52 | 53 | public void setFilename(String filename) { 54 | this.filename = filename; 55 | } 56 | 57 | public String getExtension() { 58 | return extension; 59 | } 60 | 61 | public void setExtension(String extension) { 62 | this.extension = extension; 63 | } 64 | 65 | public String getConfiguration() { 66 | return configuration; 67 | } 68 | 69 | public void setConfiguration(String configuration) { 70 | this.configuration = configuration; 71 | } 72 | 73 | public File getConfigurationFile() { 74 | return configurationFile; 75 | } 76 | 77 | public void setConfigurationFile(File configurationFile) { 78 | this.configurationFile = configurationFile; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /maven-plugin/src/it/01-minimal-setup/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 6 | minimal-setup 7 | 1.0 8 | jar 9 | 10 | 11 | 12 | Danny Althoff 13 | fibrefox@dynamicfiles.de 14 | https://www.dynamicfiles.de 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.7.0 24 | 25 | 1.8 26 | 1.8 27 | true 28 | 29 | -Xlint:unchecked 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-jar-plugin 38 | 3.0.2 39 | 40 | 41 | 42 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup.Main 43 | 44 | 45 | 46 | 47 | 48 | 49 | de.dynamicfiles.projects.maven 50 | distribution-bundle-plugin 51 | @project.version@ 52 | 53 | 54 | generate-java-bundle 55 | package 56 | 57 | java-app 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /maven-plugin/src/it/10-additional-java-app-resources/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 6 | additional-java-app-resources 7 | 1.0 8 | jar 9 | 10 | 11 | 12 | Danny Althoff 13 | fibrefox@dynamicfiles.de 14 | https://www.dynamicfiles.de 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.7.0 24 | 25 | 1.8 26 | 1.8 27 | true 28 | 29 | -Xlint:unchecked 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-jar-plugin 38 | 3.0.2 39 | 40 | 41 | 42 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup.Main 43 | 44 | 45 | 46 | 47 | 48 | 49 | de.dynamicfiles.projects.maven 50 | distribution-bundle-plugin 51 | @project.version@ 52 | 53 | 54 | generate-java-bundle 55 | package 56 | 57 | java-app 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /maven-plugin/src/it/11-zip-and-attach-as-project-artifact/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 6 | zip-and-attach-as-project-artifact 7 | 1.0 8 | jar 9 | 10 | 11 | 12 | Danny Althoff 13 | fibrefox@dynamicfiles.de 14 | https://www.dynamicfiles.de 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.7.0 24 | 25 | 1.8 26 | 1.8 27 | true 28 | 29 | -Xlint:unchecked 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-jar-plugin 38 | 3.0.2 39 | 40 | 41 | 42 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup.Main 43 | 44 | 45 | 46 | 47 | 48 | 49 | de.dynamicfiles.projects.maven 50 | distribution-bundle-plugin 51 | @project.version@ 52 | 53 | 54 | generate-java-bundle 55 | package 56 | 57 | java-app 58 | 59 | 60 | true 61 | true 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /maven-plugin/src/it/02-minimal-setup-custom-main-class/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 6 | minimal-setup-custom-main-class 7 | 1.0 8 | jar 9 | 10 | 11 | 12 | Danny Althoff 13 | fibrefox@dynamicfiles.de 14 | https://www.dynamicfiles.de 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.7.0 24 | 25 | 1.8 26 | 1.8 27 | true 28 | 29 | -Xlint:unchecked 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-jar-plugin 38 | 3.0.2 39 | 40 | 41 | 42 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetupcustommainclass.Main 43 | 44 | 45 | 46 | 47 | 48 | 49 | de.dynamicfiles.projects.maven 50 | distribution-bundle-plugin 51 | @project.version@ 52 | 53 | 54 | generate-java-bundle 55 | package 56 | 57 | java-app 58 | 59 | 60 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetupcustommainclass.SecondMain 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /maven-plugin/src/it/12-zip-and-attach-as-project-artifact-with-target-classifier/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 6 | zip-and-attach-as-project-artifact-with-target-classifier 7 | 1.0 8 | jar 9 | 10 | 11 | 12 | Danny Althoff 13 | fibrefox@dynamicfiles.de 14 | https://www.dynamicfiles.de 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.7.0 24 | 25 | 1.8 26 | 1.8 27 | true 28 | 29 | -Xlint:unchecked 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-jar-plugin 38 | 3.0.2 39 | 40 | 41 | 42 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup.Main 43 | 44 | 45 | 46 | 47 | 48 | 49 | de.dynamicfiles.projects.maven 50 | distribution-bundle-plugin 51 | @project.version@ 52 | 53 | 54 | generate-java-bundle 55 | package 56 | 57 | java-app 58 | 59 | 60 | true 61 | true 62 | app 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /maven-plugin/src/it/04-simple-spring-boot-setup/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.0.2.RELEASE 10 | 11 | 12 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 13 | simple-spring-boot-setup 14 | 1.0 15 | jar 16 | 17 | 18 | 19 | Danny Althoff 20 | fibrefox@dynamicfiles.de 21 | https://www.dynamicfiles.de 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-compiler-plugin 37 | 3.7.0 38 | 39 | 1.8 40 | 1.8 41 | true 42 | 43 | -Xlint:unchecked 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-maven-plugin 52 | 53 | 54 | 55 | de.dynamicfiles.projects.maven 56 | distribution-bundle-plugin 57 | @project.version@ 58 | 59 | 60 | generate-java-bundle 61 | package 62 | 63 | java-app 64 | 65 | 66 | 67 | 68 | false 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /bundler-spi/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/spi/NativeAppBundler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.spi; 17 | 18 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.NativeAppOptions; 19 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.OS; 20 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.SharedInternalTools; 21 | import java.io.File; 22 | import org.apache.maven.execution.MavenSession; 23 | import org.apache.maven.plugin.MojoExecution; 24 | import org.apache.maven.plugin.MojoExecutionException; 25 | import org.apache.maven.plugin.MojoFailureException; 26 | import org.apache.maven.plugin.logging.Log; 27 | import org.apache.maven.project.MavenProject; 28 | import org.apache.maven.repository.RepositorySystem; 29 | 30 | /** 31 | * 32 | * @author Danny Althoff 33 | */ 34 | public interface NativeAppBundler { 35 | 36 | /** 37 | * When having multiple bundlers inside one JAR-file, this is used to identify them. 38 | * 39 | * @return 40 | */ 41 | String getBundlerIdentifier(); 42 | 43 | /** 44 | * Bundlers might depend on locally installed tooling, therefor checking their existence or all requirements being fulfilled 45 | * can be done by this method. 46 | * 47 | * @param nativeAppOptions 48 | * @param internalUtils 49 | * @param project 50 | * @param repositorySystem 51 | * @param mojoExecution 52 | * @param session 53 | * 54 | * @return 55 | */ 56 | boolean checkRequirements(NativeAppOptions nativeAppOptions, SharedInternalTools internalUtils, MavenProject project, RepositorySystem repositorySystem, MojoExecution mojoExecution, MavenSession session, Log log); 57 | 58 | File bundleApp(NativeAppOptions nativeAppOptions, SharedInternalTools internalUtils, MavenProject project, RepositorySystem repositorySystem, MojoExecution mojoExecution, MavenSession session, Log log) throws MojoFailureException, MojoExecutionException; 59 | 60 | /** 61 | * As there is no direct help via maven, this bundler can be enhanced for showing the used additional parameters. 62 | */ 63 | void printHelp(); 64 | 65 | /** 66 | * Returns true when this bundler is being able to run on given build system. Building bundles might be dependend to build system as 67 | * native tooling is used. 68 | * 69 | * @param os 70 | * 71 | * @return true, when this bundler is callable on provided OS, otherwise false 72 | */ 73 | boolean creatableOnBuildsystem(OS os); 74 | 75 | OS getDistributionTargetOS(); 76 | } 77 | -------------------------------------------------------------------------------- /maven-plugin/src/it/06-simple-javafx-with-spring-boot-setup/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.0.2.RELEASE 10 | 11 | 12 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 13 | simple-javafx-with-spring-boot-setup 14 | 1.0 15 | jar 16 | 17 | 18 | 19 | Danny Althoff 20 | fibrefox@dynamicfiles.de 21 | https://www.dynamicfiles.de 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-compiler-plugin 37 | 3.7.0 38 | 39 | 1.8 40 | 1.8 41 | true 42 | 43 | -Xlint:unchecked 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-maven-plugin 52 | 53 | 54 | 55 | de.dynamicfiles.projects.maven 56 | distribution-bundle-plugin 57 | @project.version@ 58 | 59 | 60 | generate-java-bundle 61 | package 62 | 63 | java-app 64 | 65 | 66 | 67 | 68 | false 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /maven-plugin/src/it/05-custom-source-artifact-classifier/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.0.2.RELEASE 10 | 11 | 12 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 13 | custom-source-artifact-classifier 14 | 1.0 15 | jar 16 | 17 | 18 | 19 | Danny Althoff 20 | fibrefox@dynamicfiles.de 21 | https://www.dynamicfiles.de 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-compiler-plugin 37 | 3.7.0 38 | 39 | 1.8 40 | 1.8 41 | true 42 | 43 | -Xlint:unchecked 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-maven-plugin 52 | 53 | 54 | customsourceartifactclassifier 55 | 56 | 57 | 58 | 59 | de.dynamicfiles.projects.maven 60 | distribution-bundle-plugin 61 | @project.version@ 62 | 63 | 64 | generate-java-bundle 65 | package 66 | 67 | java-app 68 | 69 | 70 | false 71 | 72 | 73 | customsourceartifactclassifier 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | matrix: 4 | include: 5 | ## https://docs.travis-ci.com/user/reference/trusty/ 6 | ## has newer Maven 7 | - os: linux 8 | sudo: false 9 | dist: trusty 10 | jdk: oraclejdk8 11 | install: true 12 | env: FAILURES_ALLOWED=false 13 | addons: 14 | apt: 15 | packages: 16 | ## RPM 17 | - rpm 18 | ## DEB 19 | - fakeroot 20 | ## OpenJDK should work too, but TravisCI has no up2date Ubuntu-Image, makes it impossible to install OpenJFX 21 | - os: linux 22 | sudo: false 23 | dist: trusty 24 | jdk: oraclejdk9 25 | install: true 26 | env: FAILURES_ALLOWED=false 27 | addons: 28 | apt: 29 | packages: 30 | ## RPM 31 | - rpm 32 | ## DEB 33 | - fakeroot 34 | - os: linux 35 | sudo: false 36 | dist: trusty 37 | jdk: oraclejdk10 38 | install: true 39 | env: FAILURES_ALLOWED=false 40 | addons: 41 | apt: 42 | packages: 43 | ## RPM 44 | - rpm 45 | ## DEB 46 | - fakeroot 47 | # as this project is intended to be done for JDK10+, check newer version too 48 | - os: linux 49 | sudo: false 50 | dist: trusty 51 | jdk: oraclejdk-ea 52 | install: true 53 | env: FAILURES_ALLOWED=false 54 | addons: 55 | apt: 56 | packages: 57 | ## RPM 58 | - rpm 59 | ## DEB 60 | - fakeroot 61 | # as TravisCI does NOT HAVE CURRENT LTS VERSIONS, do not try to install OpenJFX :( or even try anything... 62 | # # use OpenJDK :) without OpenJFX 63 | # - os: linux 64 | # sudo: false 65 | # dist: trusty 66 | # jdk: openjdk10 67 | # install: true 68 | # env: FAILURES_ALLOWED=false 69 | # addons: 70 | # apt: 71 | # packages: 72 | # - openjfx 73 | # ## RPM 74 | # - rpm 75 | # ## DEB 76 | # - fakeroot 77 | # as this project is intended to be done for JDK10+, check newer version too 78 | - os: linux 79 | sudo: false 80 | dist: trusty 81 | jdk: openjdk11 82 | install: true 83 | env: FAILURES_ALLOWED=false 84 | addons: 85 | apt: 86 | packages: 87 | # as TravisCI does NOT HAVE CURRENT LTS VERSIONS, do not try to install OpenJFX :( 88 | # - openjfx 89 | ## RPM 90 | - rpm 91 | ## DEB 92 | - fakeroot 93 | ## has older Maven 94 | - os: linux 95 | sudo: false 96 | dist: precise 97 | jdk: oraclejdk8 98 | env: FAILURES_ALLOWED=false 99 | addons: 100 | apt: 101 | packages: 102 | ## RPM 103 | - rpm 104 | ## DEB 105 | - fakeroot 106 | ## use different OSX versions 107 | ## OS X 10.11 108 | - os: osx 109 | osx_image: xcode8 110 | env: FAILURES_ALLOWED=false 111 | ## OS X 10.12 112 | - os: osx 113 | osx_image: xcode8.3 114 | env: FAILURES_ALLOWED=false 115 | ## OS X 10.12 116 | - os: osx 117 | osx_image: xcode9.2 118 | env: FAILURES_ALLOWED=false 119 | 120 | script: 121 | - mvn install -B 122 | 123 | notifications: 124 | email: false 125 | -------------------------------------------------------------------------------- /bundler-implementations/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 4.0.0 21 | 22 | de.dynamicfiles.projects.maven.distributionbundleplugin 23 | bundler-implementations 24 | 1.0.0-SNAPSHOT 25 | 26 | pom 27 | 28 | Distribution Bundle Plugin for Maven - bundler implementations 29 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven 30 | 31 | Easy creationg of shareable software bundles for your Java application, integrated into your build-system: Maven. 32 | 33 | 2018 34 | 35 | 36 | 37 | Apache License, Version 2.0 38 | http://www.apache.org/licenses/LICENSE-2.0 39 | repo 40 | 41 | 42 | 43 | 44 | 45 | fibrefox 46 | Danny Althoff 47 | fibrefox@dynamicfiles.de 48 | 49 | Original Author 50 | 51 | 52 | 53 | 54 | 55 | scm:git:git://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 56 | scm:git:git@github.com:FibreFoX/distribution-bundle-plugin-for-maven.git 57 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 58 | 59 | 60 | 61 | GitHub 62 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven/issues 63 | 64 | 65 | 66 | 67 | ossrh 68 | https://oss.sonatype.org/content/repositories/snapshots 69 | 70 | 71 | ossrh 72 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 73 | 74 | 75 | 76 | 77 | 78 | none 79 | 80 | 81 | 82 | native-app-windows-x64 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 4.0.0 21 | 22 | de.dynamicfiles.projects.maven.distributionbundleplugin 23 | parent-project 24 | 1.0.0-SNAPSHOT 25 | 26 | pom 27 | 28 | Distribution Bundle Plugin for Maven - Parent 29 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven 30 | 31 | Easy creationg of shareable software bundles for your Java application, integrated into your build-system: Maven. 32 | 33 | 2018 34 | 35 | 36 | 37 | Apache License, Version 2.0 38 | http://www.apache.org/licenses/LICENSE-2.0 39 | repo 40 | 41 | 42 | 43 | 44 | 45 | fibrefox 46 | Danny Althoff 47 | fibrefox@dynamicfiles.de 48 | 49 | Original Author 50 | 51 | 52 | 53 | 54 | 55 | scm:git:git://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 56 | scm:git:git@github.com:FibreFoX/distribution-bundle-plugin-for-maven.git 57 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 58 | 59 | 60 | 61 | GitHub 62 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven/issues 63 | 64 | 65 | 66 | 67 | ossrh 68 | https://oss.sonatype.org/content/repositories/snapshots 69 | 70 | 71 | ossrh 72 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 73 | 74 | 75 | 76 | 77 | 78 | none 79 | 80 | 81 | 82 | 83 | bundler-spi 84 | bundler-implementations 85 | maven-plugin 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /bundler-spi/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/api/NativeAppOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.api; 17 | 18 | import java.io.File; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | /** 23 | * 24 | * @author Danny Althoff 25 | */ 26 | public class NativeAppOptions { 27 | 28 | private boolean verbose; 29 | 30 | private File sourceFolder; 31 | 32 | private File outputBaseFolder; 33 | 34 | private File tempWorkfolder; 35 | 36 | private String jdkPath; 37 | 38 | private boolean withJRE; 39 | 40 | private String jrePath; 41 | 42 | private List nativeLaunchers; 43 | 44 | private Map internalParameters; 45 | 46 | public boolean isVerbose() { 47 | return verbose; 48 | } 49 | 50 | public void setVerbose(boolean verbose) { 51 | this.verbose = verbose; 52 | } 53 | 54 | public File getSourceFolder() { 55 | return sourceFolder; 56 | } 57 | 58 | public void setSourceFolder(File sourceFolder) { 59 | this.sourceFolder = sourceFolder; 60 | } 61 | 62 | public File getOutputBaseFolder() { 63 | return outputBaseFolder; 64 | } 65 | 66 | public void setOutputBaseFolder(File outputBaseFolder) { 67 | this.outputBaseFolder = outputBaseFolder; 68 | } 69 | 70 | public File getTempWorkfolder() { 71 | return tempWorkfolder; 72 | } 73 | 74 | public void setTempWorkfolder(File tempWorkfolder) { 75 | this.tempWorkfolder = tempWorkfolder; 76 | } 77 | 78 | public String getJdkPath() { 79 | return jdkPath; 80 | } 81 | 82 | public void setJdkPath(String jdkPath) { 83 | this.jdkPath = jdkPath; 84 | } 85 | 86 | public boolean isWithJRE() { 87 | return withJRE; 88 | } 89 | 90 | public void setWithJRE(boolean withJRE) { 91 | this.withJRE = withJRE; 92 | } 93 | 94 | public String getJrePath() { 95 | return jrePath; 96 | } 97 | 98 | public void setJrePath(String jrePath) { 99 | this.jrePath = jrePath; 100 | } 101 | 102 | public List getNativeLaunchers() { 103 | return nativeLaunchers; 104 | } 105 | 106 | public void setNativeLaunchers(List nativeLaunchers) { 107 | this.nativeLaunchers = nativeLaunchers; 108 | } 109 | 110 | public Map getInternalParameters() { 111 | return internalParameters; 112 | } 113 | 114 | public void setInternalParameters(Map internalParameters) { 115 | this.internalParameters = internalParameters; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Travis Build Status](https://travis-ci.org/FibreFoX/distribution-bundle-plugin-for-maven.svg?branch=master)](https://travis-ci.org/FibreFoX/distribution-bundle-plugin-for-maven) 2 | [![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/2f2tcy40htaws9p0/branch/master?svg=true)](https://ci.appveyor.com/project/FibreFoX/distribution-bundle-plugin-for-maven/branch/master) 3 | 4 | # WORK IN PROGRESS 5 | 6 | * This will replace the [javafx-maven-plugin](https://github.com/javafx-maven-plugin/javafx-maven-plugin), as this is a rewrite of the whole contept, without the requirement for the OpenJFX/JavaFX-part being installed. It'll be JavaFX-agnostic, making it more accessable to non-JFX applications. 7 | * **pull-requests are getting ignored and closed unseed until this plugin is released** 8 | * unlike the [javafx-maven-plugin](https://github.com/javafx-maven-plugin/javafx-maven-plugin), this maven-plugin does try to not rely on the installed JavaFX/OpenJFX parts, but on short term (to make the replacement-process faster) it re-uses the files that are coming with them, so make sure to have them installed aswell (the roadmap contains a rewrite of the native launcher part, probably using RUST) 9 | * no batteries included: every bundle-type except "java-app" is done in a separate maven-project, making this maven-plugin like a nice bootstrapper for custom bundlers, and making it more flexible for having your very own way to bundle your stuff (like DromblerFX) 10 | * please look in the [test-projects](maven-plugin/src/it/) to have some insight whats coming up 11 | * I am aware of the proposal/JEP [JDK-8200758](https://bugs.openjdk.java.net/browse/JDK-8200758) regarding oracles own replacement for the javapackager, but as they did not a good job on that, and to avoid any deep dependency on that, I do not intend to re-integrate with their stuff (time will have to tell about the quality of their tool, might change my mind about it) 12 | 13 | # Easy creationg of shareable software bundles for your Java application 14 | 15 | Distributing Java software applications gets tricky sometimes, therefor this plugin integrates the creation of them into your build system (maven). 16 | 17 | # What kind of "distribution bundles" are going to be created 18 | 19 | There are three types of bundles: 20 | 1. (java-app bundle) executable jar-file with dependencies 21 | 2. (native-app bundle) executable jar-file with dependencies, with the addition of some OS native launcher files and some JRE aside 22 | 3. (native-installer bundle) all the above, packed and stuffed into some native installer file (MSI, DEB, PKG, ...) without a lot of restrictions 23 | 24 | # Available as SNAPSHOT-version 25 | 26 | To be one of the first beta-testers, just add the first available snapshot-version using the snapshot-repository from Sonatype: 27 | 28 | ```xml 29 | 30 | 31 | oss-sonatype-snapshots 32 | https://oss.sonatype.org/content/groups/public/ 33 | 34 | true 35 | 36 | 37 | 38 | ``` 39 | 40 | Add this to your ``-block: 41 | 42 | ```xml 43 | 44 | de.dynamicfiles.projects.maven 45 | distribution-bundle-plugin 46 | 1.0.0-SNAPSHOT 47 | 48 | 49 | generate-java-bundle 50 | package 51 | 52 | java-app 53 | 54 | 55 | 56 | 57 | ``` -------------------------------------------------------------------------------- /maven-plugin/src/it/07-zipped-java-app-using-spring-boot-without-fatjar/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.0.2.RELEASE 10 | 11 | 12 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 13 | zipped-java-app-using-spring-boot-without-fatjar 14 | 1.0 15 | jar 16 | 17 | 18 | 19 | Danny Althoff 20 | fibrefox@dynamicfiles.de 21 | https://www.dynamicfiles.de 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-compiler-plugin 37 | 3.7.0 38 | 39 | 1.8 40 | 1.8 41 | true 42 | 43 | -Xlint:unchecked 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-maven-plugin 52 | 53 | 54 | customsourceartifactclassifier 55 | 56 | 57 | 58 | 59 | de.dynamicfiles.projects.maven 60 | distribution-bundle-plugin 61 | @project.version@ 62 | 63 | 64 | generate-java-bundle 65 | package 66 | 67 | java-app 68 | 69 | 70 | 71 | true 72 | 73 | 74 | true 75 | 76 | 77 | 78 | 79 | 80 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.example7.MainEntrypoint 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /maven-plugin/src/it/13-generate-classpath-using-lib-folder-content/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 6 | minimal-setup 7 | 1.0 8 | jar 9 | 10 | 11 | 12 | Danny Althoff 13 | fibrefox@dynamicfiles.de 14 | https://www.dynamicfiles.de 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.7.0 24 | 25 | 1.8 26 | 1.8 27 | true 28 | 29 | -Xlint:unchecked 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-jar-plugin 38 | 3.0.2 39 | 40 | 41 | 42 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup.Main 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-dependency-plugin 52 | 3.1.1 53 | 54 | 55 | copy-some-dependency 56 | package 57 | 58 | copy 59 | 60 | 61 | org.apache.maven.plugins:maven-dependency-plugin:3.1.1 62 | ${project.build.directory}/distbundle/java-app/lib 63 | 64 | 65 | 66 | 67 | 68 | 69 | de.dynamicfiles.projects.maven 70 | distribution-bundle-plugin 71 | @project.version@ 72 | 73 | 74 | generate-java-bundle 75 | package 76 | 77 | java-app 78 | 79 | 80 | true 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /maven-plugin/src/it/08-create-keystore/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 6 | create-keystore 7 | 1.0 8 | jar 9 | 10 | 11 | 12 | Danny Althoff 13 | fibrefox@dynamicfiles.de 14 | https://www.dynamicfiles.de 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.7.0 24 | 25 | 1.8 26 | 1.8 27 | true 28 | 29 | -Xlint:unchecked 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-jar-plugin 38 | 3.0.2 39 | 40 | 41 | 42 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup.Main 43 | 44 | 45 | 46 | 47 | 48 | 49 | de.dynamicfiles.projects.maven 50 | distribution-bundle-plugin 51 | @project.version@ 52 | 53 | 54 | generate-keystore 55 | package 56 | 57 | create-temp-keystore 58 | 59 | 60 | 61 | -genkeypair 62 | -storetype 63 | pkcs12 64 | -keystore 65 | {KEYSTORE} 66 | -alias 67 | myalias 68 | -storepass 69 | changeit 70 | -keypass 71 | changeit 72 | -dname 73 | cn=YourCompany, ou=none, o=YourOrg, st=YourState, c=YourCountry 74 | -sigalg 75 | SHA256withRSA 76 | -validity 77 | 100 78 | -keyalg 79 | RSA 80 | -keysize 81 | 4096 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /maven-plugin/src/it/09-sign-minimal-setup/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | de.dynamicfiles.projects.maven.distributionbundleplugin.examples 6 | sign-minimal-setup 7 | 1.0 8 | jar 9 | 10 | 11 | 12 | Danny Althoff 13 | fibrefox@dynamicfiles.de 14 | https://www.dynamicfiles.de 15 | 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.7.0 24 | 25 | 1.8 26 | 1.8 27 | true 28 | 29 | -Xlint:unchecked 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-jar-plugin 38 | 3.0.2 39 | 40 | 41 | 42 | de.dynamicfiles.projects.maven.distributionbundleplugin.example.minimalsetup.Main 43 | 44 | 45 | 46 | 47 | 48 | 49 | de.dynamicfiles.projects.maven 50 | distribution-bundle-plugin 51 | @project.version@ 52 | 53 | 54 | 55 | generate-keystore 56 | package 57 | 58 | create-temp-keystore 59 | 60 | 61 | 62 | -genkeypair 63 | -storetype 64 | pkcs12 65 | -keystore 66 | {KEYSTORE} 67 | -alias 68 | myalias 69 | -storepass 70 | changeit 71 | -keypass 72 | changeit 73 | -dname 74 | cn=YourCompany, ou=none, o=YourOrg, st=YourState, c=YourCountry 75 | -sigalg 76 | SHA256withRSA 77 | -validity 78 | 100 79 | -keyalg 80 | RSA 81 | -keysize 82 | 4096 83 | 84 | 85 | 86 | 87 | generate-java-bundle 88 | package 89 | 90 | java-app 91 | 92 | 93 | true 94 | 95 | 96 | 97 | 98 | -storetype 99 | pkcs12 100 | -keystore 101 | ${project.basedir}/src/main/distbundle/java-app/keystore.pkcs12 102 | -storepass 103 | changeit 104 | -keypass 105 | changeit 106 | {JAR} 107 | myalias 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /bundler-spi/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 4.0.0 21 | 22 | de.dynamicfiles.projects.maven.distributionbundleplugin 23 | bundler-spi 24 | 1.0.0-SNAPSHOT 25 | 26 | jar 27 | 28 | Distribution Bundle Maven Plugin - bundler SPI project 29 | https://www.dynamicfiles.de 30 | 31 | Easy creationg of shareable software bundles for your Java application, integrated into your build-system: Maven. 32 | Each bundler used by the distribution-bundle-plugin requires to have some interface implemented. This projects provides that SPI. 33 | 34 | 2018 35 | 36 | 37 | 38 | Apache License, Version 2.0 39 | http://www.apache.org/licenses/LICENSE-2.0 40 | repo 41 | 42 | 43 | 44 | 45 | 46 | fibrefox 47 | Danny Althoff 48 | fibrefox@dynamicfiles.de 49 | 50 | Original Author 51 | 52 | 53 | 54 | 55 | 56 | scm:git:git://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 57 | scm:git:git@github.com:FibreFoX/distribution-bundle-plugin-for-maven.git 58 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 59 | 60 | 61 | 62 | GitHub 63 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven/issues 64 | 65 | 66 | 67 | 68 | ossrh 69 | https://oss.sonatype.org/content/repositories/snapshots 70 | 71 | 72 | ossrh 73 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 74 | 75 | 76 | 77 | 78 | UTF-8 79 | UTF-8 80 | 81 | 1.8 82 | 1.8 83 | 84 | 85 | false 86 | false 87 | false 88 | false 89 | 90 | 91 | none 92 | 93 | 94 | 95 | 96 | org.apache.maven 97 | maven-plugin-api 98 | 3.5.3 99 | provided 100 | 101 | 102 | org.apache.maven 103 | maven-core 104 | 3.5.3 105 | provided 106 | 107 | 108 | 109 | 110 | 111 | 112 | org.apache.maven.plugins 113 | maven-compiler-plugin 114 | 3.7.0 115 | 116 | ${maven.compiler.source} 117 | ${maven.compiler.target} 118 | true 119 | 120 | -Xlint:unchecked 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | generate-signed-files 130 | 131 | 132 | doSign 133 | true 134 | 135 | 136 | 137 | 138 | 139 | 140 | org.apache.maven.plugins 141 | maven-gpg-plugin 142 | 1.6 143 | 144 | 145 | sign-artifacts 146 | verify 147 | 148 | sign 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | generate-source-files 158 | 159 | 160 | withSrc 161 | true 162 | 163 | 164 | 165 | 166 | 167 | org.apache.maven.plugins 168 | maven-source-plugin 169 | 3.0.1 170 | 171 | 172 | generate-sources-jar 173 | package 174 | 175 | jar-no-fork 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | generate-javadoc-files 185 | 186 | 187 | withDoc 188 | true 189 | 190 | 191 | 192 | 193 | 194 | org.apache.maven.plugins 195 | maven-javadoc-plugin 196 | 3.0.1 197 | 198 | 199 | generate-javadoc-jar 200 | package 201 | 202 | javadoc-no-fork 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | release-to-ossrh 212 | 213 | 214 | doRelease 215 | true 216 | 217 | 218 | 219 | 220 | 221 | org.sonatype.plugins 222 | nexus-staging-maven-plugin 223 | 1.6.8 224 | true 225 | 226 | ossrh 227 | https://oss.sonatype.org/ 228 | false 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /bundler-implementations/native-app-windows-x64/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 4.0.0 21 | 22 | de.dynamicfiles.projects.maven.distributionbundleplugin.bundler 23 | native-app-windows-x64 24 | 1.0.0-SNAPSHOT 25 | 26 | jar 27 | 28 | Distribution Bundle Plugin for Maven - bundler implementation - Windows native 64bit 29 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven 30 | 31 | Easy creationg of shareable software bundles for your Java application, integrated into your build-system: Maven. 32 | 33 | 2018 34 | 35 | 36 | 37 | Apache License, Version 2.0 38 | http://www.apache.org/licenses/LICENSE-2.0 39 | repo 40 | 41 | 42 | 43 | 44 | 45 | fibrefox 46 | Danny Althoff 47 | fibrefox@dynamicfiles.de 48 | 49 | Original Author 50 | 51 | 52 | 53 | 54 | 55 | scm:git:git://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 56 | scm:git:git@github.com:FibreFoX/distribution-bundle-plugin-for-maven.git 57 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 58 | 59 | 60 | 61 | GitHub 62 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven/issues 63 | 64 | 65 | 66 | 67 | ossrh 68 | https://oss.sonatype.org/content/repositories/snapshots 69 | 70 | 71 | ossrh 72 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 73 | 74 | 75 | 76 | 77 | UTF-8 78 | UTF-8 79 | 80 | 1.8 81 | 1.8 82 | 83 | 84 | false 85 | false 86 | false 87 | false 88 | 89 | 90 | none 91 | 92 | 93 | 94 | 95 | org.apache.maven 96 | maven-plugin-api 97 | 3.5.3 98 | provided 99 | 100 | 101 | org.apache.maven 102 | maven-core 103 | 3.5.3 104 | provided 105 | 106 | 107 | de.dynamicfiles.projects.maven.distributionbundleplugin 108 | bundler-spi 109 | 1.0.0-SNAPSHOT 110 | 111 | 112 | 113 | 114 | 115 | 116 | org.apache.maven.plugins 117 | maven-compiler-plugin 118 | 3.7.0 119 | 120 | 1.8 121 | 1.8 122 | true 123 | 124 | -Xlint:unchecked 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | generate-signed-files 134 | 135 | 136 | doSign 137 | true 138 | 139 | 140 | 141 | 142 | 143 | 144 | org.apache.maven.plugins 145 | maven-gpg-plugin 146 | 1.6 147 | 148 | 149 | sign-artifacts 150 | verify 151 | 152 | sign 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | generate-source-files 162 | 163 | 164 | withSrc 165 | true 166 | 167 | 168 | 169 | 170 | 171 | org.apache.maven.plugins 172 | maven-source-plugin 173 | 3.0.1 174 | 175 | 176 | generate-sources-jar 177 | package 178 | 179 | jar-no-fork 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | generate-javadoc-files 189 | 190 | 191 | withDoc 192 | true 193 | 194 | 195 | 196 | 197 | 198 | org.apache.maven.plugins 199 | maven-javadoc-plugin 200 | 3.0.1 201 | 202 | 203 | generate-javadoc-jar 204 | package 205 | 206 | javadoc-no-fork 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | release-to-ossrh 216 | 217 | 218 | doRelease 219 | true 220 | 221 | 222 | 223 | 224 | 225 | org.sonatype.plugins 226 | nexus-staging-maven-plugin 227 | 1.6.8 228 | true 229 | 230 | ossrh 231 | https://oss.sonatype.org/ 232 | false 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | -------------------------------------------------------------------------------- /maven-plugin/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/mojo/CreateTempKeystore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.mojo; 17 | 18 | import de.dynamicfiles.projects.maven.distributionbundleplugin.InternalUtils; 19 | import java.io.File; 20 | import java.io.IOException; 21 | import java.nio.file.Files; 22 | import java.nio.file.LinkOption; 23 | import java.nio.file.Path; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.concurrent.atomic.AtomicReference; 27 | import java.util.stream.Collectors; 28 | import org.apache.maven.plugin.AbstractMojo; 29 | import org.apache.maven.plugin.MojoExecutionException; 30 | import org.apache.maven.plugin.MojoFailureException; 31 | import org.apache.maven.plugins.annotations.Mojo; 32 | import org.apache.maven.plugins.annotations.Parameter; 33 | import org.apache.maven.plugins.annotations.ResolutionScope; 34 | import org.apache.maven.project.MavenProject; 35 | 36 | /** 37 | * While developing it sometimes is required to have a valid keystore. 38 | * 39 | * @author Danny Althoff 40 | */ 41 | @Mojo(name = "create-temp-keystore", requiresDependencyResolution = ResolutionScope.NONE) 42 | public class CreateTempKeystore extends AbstractMojo { 43 | 44 | @Parameter(defaultValue = "${project}", readonly = true) 45 | private MavenProject project; 46 | 47 | /** 48 | * Enable to see some status messages. 49 | */ 50 | @Parameter(defaultValue = "true") 51 | private boolean verbose; 52 | 53 | /** 54 | * In case you have a special JDK to be used for creating, please specify this here. Expects some extracted/installed JDK. 55 | */ 56 | @Parameter(defaultValue = "${java.home}") 57 | private String jdkPath; 58 | 59 | /** 60 | * Specify the target location of the generated keystore. 61 | */ 62 | @Parameter(defaultValue = "${project.basedir}/src/main/distbundle/java-app/keystore.pkcs12") 63 | private File keystore; 64 | 65 | /** 66 | * To protect from accidentally overwriting some existing keystore, overwriting has to be enabled. 67 | */ 68 | @Parameter(defaultValue = "false") 69 | private boolean overwriteKeystore; 70 | 71 | /** 72 | * For creating a keystore the tool "keytool" of the used JDK gets used. Here you have to specify the used parameters for the 73 | * keystore creation process. As the position of the jks-file might vary, just use "{KEYSTORE}" as placeholder, which gets replaced by the filename being created. 74 | * 75 | * For further details about the available parameters, please consult the keytool documentation. 76 | * 77 | * Example-configuration: 78 | * 79 | * <createParameters> 80 | * <parameter>-genkeypair</parameter> 81 | * <parameter>-storetype</parameter> 82 | * <parameter>pkcs12</parameter> 83 | * <parameter>-keystore</parameter> 84 | * <parameter>{KEYSTORE}</parameter> 85 | * <parameter>-alias</parameter> 86 | * <parameter>myalias</parameter> 87 | * <parameter>-storepass</parameter> 88 | * <parameter>changeit</parameter> 89 | * <parameter>-keypass</parameter> 90 | * <parameter>changeit</parameter> 91 | * <parameter>-dname</parameter> 92 | * <parameter>cn=YourCompany, ou=none, o=YourOrg, st=YourState, c=YourCountry</parameter> 93 | * <parameter>-sigalg</parameter> 94 | * <parameter>SHA256withRSA</parameter> 95 | * <parameter>-validity</parameter> 96 | * <parameter>100</parameter> 97 | * <parameter>-keyalg</parameter> 98 | * <parameter>RSA</parameter> 99 | * <parameter>-keysize</parameter> 100 | * <parameter>4096</parameter> 101 | * </createParameters> 102 | * 103 | * 104 | * Note: When having verbose set to "true", the parameter "-v" gets added to this parameter-list too. 105 | * 106 | */ 107 | @Parameter 108 | private List createParameters; 109 | 110 | private final InternalUtils internalUtils = new InternalUtils(); 111 | 112 | @Override 113 | public void execute() throws MojoExecutionException, MojoFailureException { 114 | if( keystore != null && keystore.exists() && !overwriteKeystore ){ 115 | throw new MojoFailureException("Keystore is already existing, but plugin-configuration is not allowing to overwrite."); 116 | } 117 | if( keystore != null && keystore.exists() && overwriteKeystore ){ 118 | if( verbose ){ 119 | getLog().info("Overwriting keystore at: " + keystore.getAbsolutePath()); 120 | } 121 | } 122 | 123 | if( createParameters == null || createParameters.isEmpty() ){ 124 | throw new MojoFailureException("Missing configuration of 'createParameters'-parameter. Please check your plugin-configuration."); 125 | } 126 | 127 | // prepare target area 128 | try{ 129 | Files.createDirectories(keystore.toPath().getParent()); 130 | } catch(IOException ex){ 131 | throw new MojoFailureException("Could not create folder for keystore at: " + keystore.getAbsolutePath(), ex); 132 | } 133 | 134 | // find keytool 135 | Path jdkLocationPath = new File(jdkPath).toPath(); 136 | // speculation: in case of older JDKs, the "java.home" property is the JRE inside the JDK, so if we can detect the "java"-binary inside 137 | // parent folder-structure, we are using JDK prior JDK 9 138 | // otherwise we are using that folder and are looking for keytool inside the "bin"-folder, which is valid for normal JDK 9+ and when 139 | // having customized jdkHome being set manually inside plugin-configuration 140 | String platformExecutableFileExtension = internalUtils.isPlatformWindows() ? ".exe" : ""; 141 | boolean isJreInsideJdk = Files.exists(jdkLocationPath.getParent().resolve("bin").resolve("java" + platformExecutableFileExtension), LinkOption.NOFOLLOW_LINKS); 142 | AtomicReference pathToKeytool = new AtomicReference<>(); 143 | if( isJreInsideJdk ){ 144 | // look inside parent folder 145 | Path jarSignerPath = jdkLocationPath.getParent().resolve("bin").resolve("keytool" + platformExecutableFileExtension).toAbsolutePath(); 146 | if( Files.exists(jarSignerPath, LinkOption.NOFOLLOW_LINKS) ){ 147 | pathToKeytool.set(jarSignerPath.toString()); 148 | } 149 | } else { 150 | // look inside given folder, should be the default-case since JDK 9+ 151 | Path keytoolPath = jdkLocationPath.resolve("bin").resolve("keytool" + platformExecutableFileExtension).toAbsolutePath(); 152 | if( Files.exists(keytoolPath, LinkOption.NOFOLLOW_LINKS) ){ 153 | pathToKeytool.set(keytoolPath.toString()); 154 | } 155 | } 156 | 157 | if( pathToKeytool.get() == null ){ 158 | throw new MojoFailureException("Could not find keytool-executable, please check your JDK-installation of the configured JDK for this plugin-configuration."); 159 | } 160 | 161 | List createCommand = new ArrayList<>(); 162 | 163 | createCommand.add(pathToKeytool.get()); 164 | 165 | if( verbose ){ 166 | boolean alreadyContainsVerboseFlag = createParameters.stream().filter(parameter -> parameter.trim().equalsIgnoreCase("-v")).count() > 0; 167 | if( !alreadyContainsVerboseFlag ){ 168 | createCommand.add("-v"); 169 | } 170 | } 171 | 172 | createCommand.addAll(createParameters); 173 | 174 | // replace {KEYSTORE}-template with real filename 175 | List createCommandToUse = createCommand.stream().map(creatingParameter -> { 176 | if( "{KEYSTORE}".equalsIgnoreCase(creatingParameter) ){ 177 | return keystore.getAbsolutePath(); 178 | } 179 | return creatingParameter; 180 | }).collect(Collectors.toList()); 181 | 182 | try{ 183 | ProcessBuilder pb = new ProcessBuilder() 184 | .inheritIO() 185 | .directory(project.getBasedir()) 186 | .command(createCommandToUse); 187 | 188 | if( verbose ){ 189 | getLog().info("Running command: " + String.join(" ", createCommandToUse)); 190 | } 191 | 192 | Process p = pb.start(); 193 | p.waitFor(); 194 | if( p.exitValue() != 0 ){ 195 | throw new MojoExecutionException("Creating temporary keystore wasn't successful! Please check build-log."); 196 | } 197 | } catch(IOException | InterruptedException ex){ 198 | throw new MojoExecutionException("There was an exception while signing jar-file: " + keystore.getAbsolutePath(), ex); 199 | } 200 | } 201 | 202 | } 203 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /maven-plugin/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/InternalUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin; 17 | 18 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.SharedInternalTools; 19 | import java.io.File; 20 | import java.io.FileOutputStream; 21 | import java.io.IOException; 22 | import java.nio.ByteOrder; 23 | import java.nio.MappedByteBuffer; 24 | import java.nio.channels.FileChannel; 25 | import java.nio.file.FileVisitResult; 26 | import java.nio.file.FileVisitor; 27 | import java.nio.file.Files; 28 | import java.nio.file.Path; 29 | import java.nio.file.SimpleFileVisitor; 30 | import java.nio.file.StandardCopyOption; 31 | import java.nio.file.StandardOpenOption; 32 | import java.nio.file.attribute.BasicFileAttributes; 33 | import java.util.concurrent.atomic.AtomicBoolean; 34 | import java.util.jar.JarFile; 35 | import java.util.logging.Level; 36 | import java.util.logging.Logger; 37 | import java.util.zip.ZipEntry; 38 | import java.util.zip.ZipOutputStream; 39 | 40 | /** 41 | * Some methods which are used internally. This class is shared to each bundler, making it easy to re-used already existing cool stuff. 42 | * 43 | * @author Danny Althoff 44 | */ 45 | public class InternalUtils implements SharedInternalTools { 46 | 47 | @Override 48 | public boolean copyRecursive(Path sourceFolder, Path targetFolder) throws IOException { 49 | AtomicBoolean failed = new AtomicBoolean(false); 50 | Files.walkFileTree(sourceFolder, new FileVisitor() { 51 | 52 | @Override 53 | public FileVisitResult preVisitDirectory(Path subfolder, BasicFileAttributes attrs) throws IOException { 54 | // do create subfolder (if needed) 55 | Files.createDirectories(targetFolder.resolve(sourceFolder.relativize(subfolder))); 56 | return FileVisitResult.CONTINUE; 57 | } 58 | 59 | @Override 60 | public FileVisitResult visitFile(Path sourceFile, BasicFileAttributes attrs) throws IOException { 61 | // do copy, and replace, as the resource might already be existing 62 | Files.copy(sourceFile, targetFolder.resolve(sourceFolder.relativize(sourceFile)), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); 63 | return FileVisitResult.CONTINUE; 64 | } 65 | 66 | @Override 67 | public FileVisitResult visitFileFailed(Path source, IOException ioe) throws IOException { 68 | // don't fail, just inform user 69 | failed.set(true); 70 | return FileVisitResult.CONTINUE; 71 | } 72 | 73 | @Override 74 | public FileVisitResult postVisitDirectory(Path source, IOException ioe) throws IOException { 75 | // nothing to do here 76 | if( ioe != null ){ 77 | failed.set(true); 78 | } 79 | return FileVisitResult.CONTINUE; 80 | } 81 | }); 82 | return failed.get(); 83 | } 84 | 85 | @Override 86 | public boolean deleteRecursive(Path sourceFolder) throws IOException { 87 | AtomicBoolean failed = new AtomicBoolean(false); 88 | Files.walkFileTree(sourceFolder, new FileVisitor() { 89 | 90 | @Override 91 | public FileVisitResult preVisitDirectory(Path subfolder, BasicFileAttributes attrs) throws IOException { 92 | return FileVisitResult.CONTINUE; 93 | } 94 | 95 | @Override 96 | public FileVisitResult visitFile(Path sourceFile, BasicFileAttributes attrs) throws IOException { 97 | Files.deleteIfExists(sourceFile); 98 | return FileVisitResult.CONTINUE; 99 | } 100 | 101 | @Override 102 | public FileVisitResult visitFileFailed(Path source, IOException ioe) throws IOException { 103 | failed.set(true); 104 | return FileVisitResult.TERMINATE; 105 | } 106 | 107 | @Override 108 | public FileVisitResult postVisitDirectory(Path source, IOException ioe) throws IOException { 109 | if( ioe != null ){ 110 | failed.set(true); 111 | return FileVisitResult.TERMINATE; 112 | } 113 | Files.deleteIfExists(source); 114 | return FileVisitResult.CONTINUE; 115 | } 116 | }); 117 | return failed.get(); 118 | } 119 | 120 | @Override 121 | public void pack(final Path folder, final Path zipFilePath) throws IOException { 122 | // source of inspiration: http://stackoverflow.com/a/35158142/1961102 123 | try(FileOutputStream fos = new FileOutputStream(zipFilePath.toFile()); ZipOutputStream zos = new ZipOutputStream(fos)){ 124 | Files.walkFileTree(folder, new SimpleFileVisitor() { 125 | @Override 126 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 127 | // sanitize windows path parts, because ZIP only allows normal slash 128 | zos.putNextEntry(new ZipEntry(folder.relativize(file).toString().replace("\\", "/"))); 129 | Files.copy(file, zos); 130 | zos.closeEntry(); 131 | return FileVisitResult.CONTINUE; 132 | } 133 | }); 134 | } 135 | } 136 | 137 | @Override 138 | public boolean isClassInsideJarFile(String classname, String locationPrefix, File jarFile) { 139 | String requestedJarEntryName = locationPrefix + classname.replace(".", "/") + ".class"; 140 | try{ 141 | JarFile jarFileToSearchIn = new JarFile(jarFile, false, JarFile.OPEN_READ); 142 | return jarFileToSearchIn.stream().parallel().filter(jarEntry -> { 143 | return jarEntry.getName().equals(requestedJarEntryName); 144 | }).findAny().isPresent(); 145 | } catch(IOException ex){ 146 | // NO-OP 147 | } 148 | return false; 149 | } 150 | 151 | @Override 152 | public boolean isPlatformWindows() { 153 | return System.getProperty("os.name").toLowerCase().contains("win"); 154 | } 155 | 156 | @Override 157 | public boolean isPlatformLinux() { 158 | return System.getProperty("os.name").toLowerCase().contains("nix") || System.getProperty("os.name").toLowerCase().contains("nux"); 159 | } 160 | 161 | @Override 162 | public boolean isPlatformMac() { 163 | return System.getProperty("os.name").toLowerCase().contains("mac"); 164 | } 165 | 166 | @Override 167 | public boolean isLinuxExecutable64bit(Path linuxBinary) { 168 | if( !(Files.isRegularFile(linuxBinary) || Files.isSymbolicLink(linuxBinary)) || !Files.isReadable(linuxBinary) ){ 169 | return false; 170 | } 171 | 172 | try(FileChannel openFileChannel = FileChannel.open(linuxBinary, StandardOpenOption.READ)){ 173 | MappedByteBuffer startMarker = openFileChannel.map(FileChannel.MapMode.READ_ONLY, 0, 4); 174 | startMarker.load(); 175 | if( startMarker.get(0) == 0x7F && startMarker.get(1) == 'E' && startMarker.get(2) == 'L' && startMarker.get(3) == 'F' ){ 176 | // e_machine inside Elf*_Ehdr 177 | MappedByteBuffer architectureBytes = openFileChannel.map(FileChannel.MapMode.READ_ONLY, 18, 2); 178 | architectureBytes.load(); 179 | short architectureShort = architectureBytes.getShort(); 180 | // https://stackoverflow.com/a/7932774/1961102 181 | int architectureAsInt = architectureShort >= 0 ? architectureShort : 0x10000 + architectureShort; 182 | 183 | // http://www.sco.com/developers/gabi/1998-04-29/ch4.eheader.html 184 | // https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header 185 | // 32 bit 186 | if( architectureAsInt == 0x03 ){ 187 | return false; 188 | } 189 | 190 | // 64 bit (x86-64) 191 | if( architectureAsInt == 0x3E ){ 192 | return true; 193 | } 194 | } 195 | 196 | } catch(IOException ex){ 197 | Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex); 198 | } 199 | return false; 200 | } 201 | 202 | @Override 203 | public boolean isWindowsExecutable64bit(Path windowsBinary) { 204 | if( !(Files.isRegularFile(windowsBinary) || Files.isSymbolicLink(windowsBinary)) || !Files.isReadable(windowsBinary) ){ 205 | return false; 206 | } 207 | 208 | // try to find PE-header offset inside MS-DOS header and check architecture 209 | try(FileChannel openFileChannel = FileChannel.open(windowsBinary, StandardOpenOption.READ)){ 210 | MappedByteBuffer startMarker = openFileChannel.map(FileChannel.MapMode.READ_ONLY, 0, 2); 211 | startMarker.load(); 212 | if( startMarker.get(0) == 'M' && startMarker.get(1) == 'Z' ){ 213 | // found MS-DOS header magic bytes 214 | 215 | // MS-DOS header contains 4 byte PE-offset at 0x60 (e_lfanew in MZ structure) 216 | MappedByteBuffer offsetMarker = openFileChannel.map(FileChannel.MapMode.READ_ONLY, 60, 4); 217 | offsetMarker.load(); 218 | offsetMarker.order(ByteOrder.LITTLE_ENDIAN); 219 | int foundOffset = offsetMarker.getInt(); 220 | // make it positive in case of huge offset-gap 221 | foundOffset = foundOffset >= 0 ? foundOffset : 0x10000 + foundOffset; 222 | // TODO put into log on verbose 223 | // System.out.println("Found PE-Header offset: " + foundOffset); 224 | 225 | if( foundOffset > 0 ){ 226 | // found PE header offset, reading the next 6 bytes should be enough to verify 227 | MappedByteBuffer peHeader = openFileChannel.map(FileChannel.MapMode.READ_ONLY, foundOffset, 6); 228 | peHeader.load(); 229 | peHeader.order(ByteOrder.LITTLE_ENDIAN); 230 | if( peHeader.get(0) == 'P' && peHeader.get(1) == 'E' && peHeader.get(2) == '\0' && peHeader.get(3) == '\0' ){ 231 | // TODO put into log on verbose 232 | // found legal PE header, now reading architecture (first bytes from COFF header) 233 | short architectureShort = peHeader.getShort(4); 234 | // https://stackoverflow.com/a/7932774/1961102 235 | int architectureAsInt = architectureShort >= 0 ? architectureShort : 0x10000 + architectureShort; 236 | 237 | // https://msdn.microsoft.com/library/windows/desktop/ms680547(v=vs.85).aspx?id=19509#machine_types 238 | // 32bit 239 | if( architectureAsInt == 0x014c ){ 240 | return false; 241 | } 242 | // 64bit 243 | if( architectureAsInt == 0x8664 ){ 244 | return true; 245 | } 246 | // TODO put into log on verbose: different/unsupported architecture 247 | // TODO might want to check within COFF header for characteristics being exe, not DLL 248 | // TODO might want to check within "PE Optional Header" if subsystem is gui/cli 249 | } 250 | } 251 | } 252 | } catch(IOException ex){ 253 | Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex); 254 | } 255 | 256 | return false; 257 | } 258 | 259 | // TODO find out how to check mac-executables being 64bit (do I even need this anyway?) 260 | } 261 | -------------------------------------------------------------------------------- /maven-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 4.0.0 21 | 22 | de.dynamicfiles.projects.maven 23 | distribution-bundle-plugin 24 | 1.0.0-SNAPSHOT 25 | 26 | maven-plugin 27 | 28 | Distribution Bundle Plugin for Maven 29 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven 30 | 31 | Easy creationg of shareable software bundles for your Java application, integrated into your build-system: Maven. 32 | 33 | 2018 34 | 35 | 36 | 37 | Apache License, Version 2.0 38 | http://www.apache.org/licenses/LICENSE-2.0 39 | repo 40 | 41 | 42 | 43 | 44 | 45 | fibrefox 46 | Danny Althoff 47 | fibrefox@dynamicfiles.de 48 | 49 | Original Author 50 | 51 | 52 | 53 | 54 | 55 | scm:git:git://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 56 | scm:git:git@github.com:FibreFoX/distribution-bundle-plugin-for-maven.git 57 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven.git 58 | 59 | 60 | 61 | GitHub 62 | https://github.com/FibreFoX/distribution-bundle-plugin-for-maven/issues 63 | 64 | 65 | 66 | 67 | ossrh 68 | https://oss.sonatype.org/content/repositories/snapshots 69 | 70 | 71 | ossrh 72 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.apache.maven.plugins 80 | maven-plugin-plugin 81 | 3.5.2 82 | 83 | 84 | 85 | 86 | 87 | UTF-8 88 | UTF-8 89 | 90 | 1.8 91 | 1.8 92 | 93 | 94 | false 95 | false 96 | false 97 | false 98 | 99 | 100 | none 101 | 102 | 103 | 104 | 105 | org.apache.maven 106 | maven-plugin-api 107 | 3.5.3 108 | provided 109 | 110 | 111 | org.apache.maven.plugin-tools 112 | maven-plugin-annotations 113 | 3.5.1 114 | true 115 | provided 116 | 117 | 118 | org.apache.maven 119 | maven-core 120 | 3.5.3 121 | provided 122 | 123 | 124 | 125 | de.dynamicfiles.projects.maven.distributionbundleplugin 126 | bundler-spi 127 | 1.0.0-SNAPSHOT 128 | 129 | 130 | 131 | 132 | 133 | 134 | org.apache.maven.plugins 135 | maven-compiler-plugin 136 | 3.7.0 137 | 138 | 1.8 139 | 1.8 140 | true 141 | 142 | -Xlint:unchecked 143 | 144 | 145 | 146 | 147 | org.apache.maven.plugins 148 | maven-plugin-plugin 149 | 3.5.2 150 | 151 | distbundle 152 | true 153 | 154 | 155 | 156 | mojo-descriptor 157 | 158 | descriptor 159 | 160 | 161 | 162 | help-goal 163 | 164 | helpmojo 165 | 166 | 167 | 168 | 169 | 170 | org.apache.maven.plugins 171 | maven-enforcer-plugin 172 | 3.0.0-M1 173 | 174 | 175 | enforce-versions 176 | 177 | enforce 178 | 179 | 180 | 181 | 182 | [1.8,) 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | maven-invoker-plugin 192 | 3.1.0 193 | 194 | src/it 195 | target/local-repo 196 | ${project.build.directory}/it 197 | src/it/settings.xml 198 | true 199 | true 200 | ${skipTests} 201 | verify.bsh 202 | 203 | 204 | 205 | integration-test 206 | 207 | install 208 | run 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | generate-signed-files 219 | 220 | 221 | doSign 222 | true 223 | 224 | 225 | 226 | 227 | 228 | 229 | org.apache.maven.plugins 230 | maven-gpg-plugin 231 | 1.6 232 | 233 | 234 | sign-artifacts 235 | verify 236 | 237 | sign 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | generate-source-files 247 | 248 | 249 | withSrc 250 | true 251 | 252 | 253 | 254 | 255 | 256 | org.apache.maven.plugins 257 | maven-source-plugin 258 | 3.0.1 259 | 260 | 261 | generate-sources-jar 262 | package 263 | 264 | jar-no-fork 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | generate-javadoc-files 274 | 275 | 276 | withDoc 277 | true 278 | 279 | 280 | 281 | 282 | 283 | org.apache.maven.plugins 284 | maven-javadoc-plugin 285 | 3.0.1 286 | 287 | 288 | generate-javadoc-jar 289 | package 290 | 291 | javadoc-no-fork 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | release-to-ossrh 301 | 302 | 303 | doRelease 304 | true 305 | 306 | 307 | 308 | 309 | 310 | org.sonatype.plugins 311 | nexus-staging-maven-plugin 312 | 1.6.8 313 | true 314 | 315 | ossrh 316 | https://oss.sonatype.org/ 317 | false 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | -------------------------------------------------------------------------------- /bundler-implementations/native-app-windows-x64/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/bundler/nativeapp/windows/x64/NativeAppBundlerUsingResourcesFromOracleJDK.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.bundler.nativeapp.windows.x64; 17 | 18 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.NativeAppOptions; 19 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.OS; 20 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.SharedInternalTools; 21 | import de.dynamicfiles.projects.maven.distributionbundleplugin.spi.NativeAppBundler; 22 | import java.io.BufferedReader; 23 | import java.io.File; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.io.InputStreamReader; 27 | import java.nio.file.FileVisitResult; 28 | import java.nio.file.FileVisitor; 29 | import java.nio.file.Files; 30 | import java.nio.file.LinkOption; 31 | import java.nio.file.Path; 32 | import java.nio.file.StandardCopyOption; 33 | import java.nio.file.attribute.BasicFileAttributes; 34 | import java.util.ArrayList; 35 | import java.util.Arrays; 36 | import java.util.List; 37 | import java.util.Map; 38 | import java.util.Optional; 39 | import java.util.Properties; 40 | import java.util.concurrent.atomic.AtomicReference; 41 | import java.util.stream.Collectors; 42 | import org.apache.maven.execution.MavenSession; 43 | import org.apache.maven.plugin.MojoExecution; 44 | import org.apache.maven.plugin.MojoExecutionException; 45 | import org.apache.maven.plugin.MojoFailureException; 46 | import org.apache.maven.plugin.logging.Log; 47 | import org.apache.maven.project.MavenProject; 48 | import org.apache.maven.repository.RepositorySystem; 49 | 50 | /** 51 | * 52 | * @author Danny Althoff 53 | */ 54 | public class NativeAppBundlerUsingResourcesFromOracleJDK implements NativeAppBundler { 55 | 56 | protected final String jmodWithLauncherBinaries = "jdk.packager.jmod"; 57 | 58 | @Override 59 | public File bundleApp(NativeAppOptions nativeAppOptions, SharedInternalTools internalUtils, MavenProject project, RepositorySystem repositorySystem, MojoExecution mojoExecution, MavenSession session, Log logger) throws MojoFailureException, MojoExecutionException { 60 | // as since JDK 9 the resource-files are inside a jmod-file (non opened), as a workaround I'm using 61 | // the "jmod"-binary to extract the whole "jdk.packager.jmod"-file temporary 62 | // "native binaries" (bootstrapping launchers) are expecting the application sitting inside some "app"-folder aside of the native launcher 63 | // .\jmod.exe extract --dir C:\Users\FibreFoX\Desktop\blub ..\jmods\jdk.packager.jmod 64 | File outputFolderForJavaApp = nativeAppOptions.getOutputBaseFolder().toPath().resolve("windows-x64").resolve("app").toFile(); 65 | if( !outputFolderForJavaApp.exists() && !outputFolderForJavaApp.mkdirs() ){ 66 | throw new MojoFailureException("Not possible to create output folder: " + outputFolderForJavaApp.getAbsolutePath()); 67 | } 68 | 69 | // copy source bundle to nested app-folder (requirement of the native launcher from the jdk-executable) 70 | try{ 71 | internalUtils.copyRecursive(nativeAppOptions.getSourceFolder().toPath(), outputFolderForJavaApp.toPath()); 72 | } catch(IOException ex){ 73 | throw new MojoFailureException(null, ex); 74 | } 75 | 76 | boolean isUsingJmodFiles = Files.exists(new File(nativeAppOptions.getJdkPath()).toPath().resolve("jmods"), LinkOption.NOFOLLOW_LINKS); 77 | if( isUsingJmodFiles ){ 78 | // check if required jmod file is existing 79 | if( !new File(nativeAppOptions.getJdkPath()).toPath().resolve("jmods").resolve(jmodWithLauncherBinaries).toFile().exists() ){ 80 | throw new MojoExecutionException("Missing JMOD-file: " + jmodWithLauncherBinaries); 81 | } 82 | 83 | List command = new ArrayList<>(); 84 | // use the jmod-command from the provided JDK-path (might be a different version, where something has changed 85 | command.add(new File(nativeAppOptions.getJdkPath()).getAbsolutePath() + File.separator + "bin" + File.separator + "jmod.exe"); 86 | command.add("extract"); 87 | command.add("--dir"); 88 | command.add(nativeAppOptions.getTempWorkfolder().getAbsolutePath()); 89 | command.add(nativeAppOptions.getJdkPath() + File.separator + "jmods" + File.separator + jmodWithLauncherBinaries); 90 | 91 | if( nativeAppOptions.isVerbose() ){ 92 | logger.info("Executing command: " + String.join(" ", command)); 93 | } 94 | 95 | ProcessBuilder extractionProcess = new ProcessBuilder() 96 | .inheritIO() 97 | .directory(new File(project.getBuild().getDirectory())) 98 | .command(command); 99 | try{ 100 | Process p = extractionProcess.start(); 101 | p.waitFor(); 102 | if( p.exitValue() != 0 ){ 103 | throw new MojoExecutionException("Could not extract JMOD " + jmodWithLauncherBinaries); 104 | } 105 | } catch(IOException | InterruptedException ex){ 106 | throw new MojoExecutionException(null, ex); 107 | } 108 | Path windowsBinariesSource = nativeAppOptions.getTempWorkfolder().toPath().resolve("classes").resolve("com").resolve("oracle").resolve("tools").resolve("packager").resolve("windows"); 109 | 110 | // copy all DLL-files 111 | try{ 112 | Path targetFolder = nativeAppOptions.getOutputBaseFolder().toPath().resolve("windows-x64"); 113 | // TODO refactor this into utils-method for single-level-copy 114 | Files.walkFileTree(windowsBinariesSource, new FileVisitor() { 115 | 116 | boolean enteredFolder = false; 117 | 118 | @Override 119 | public FileVisitResult preVisitDirectory(Path subfolder, BasicFileAttributes attrs) throws IOException { 120 | if( enteredFolder ){ 121 | return FileVisitResult.SKIP_SUBTREE; 122 | } 123 | enteredFolder = true; 124 | return FileVisitResult.CONTINUE; 125 | } 126 | 127 | @Override 128 | public FileVisitResult visitFile(Path sourceFile, BasicFileAttributes attrs) throws IOException { 129 | // do copy, and replace, as the resource might already be existing 130 | if( sourceFile.toFile().getName().endsWith(".dll") ){ 131 | Files.copy(sourceFile, targetFolder.resolve(windowsBinariesSource.relativize(sourceFile)), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); 132 | } 133 | return FileVisitResult.CONTINUE; 134 | } 135 | 136 | @Override 137 | public FileVisitResult visitFileFailed(Path source, IOException ioe) throws IOException { 138 | // fail fast 139 | return FileVisitResult.TERMINATE; 140 | } 141 | 142 | @Override 143 | public FileVisitResult postVisitDirectory(Path source, IOException ioe) throws IOException { 144 | // nothing to do here 145 | return FileVisitResult.CONTINUE; 146 | } 147 | }); 148 | } catch(IOException ex){ 149 | if( nativeAppOptions.isVerbose() ){ 150 | logger.error(null, ex); 151 | } 152 | } 153 | 154 | // copy launcher files 155 | Path windowsLauncherBinary = windowsBinariesSource.resolve("WinLauncher.exe"); 156 | 157 | // check architecutre matching 158 | boolean bitCheckOfLauncherMatching = internalUtils.isWindowsExecutable64bit(windowsLauncherBinary); 159 | if( !bitCheckOfLauncherMatching ){ 160 | // 32 bit -> quit work, wrong configured jdk 161 | throw new MojoExecutionException("Provided JDK did not contain correct bit architecture, please provide some 64bit JDK"); 162 | } 163 | 164 | nativeAppOptions.getNativeLaunchers().forEach(nativeLauncher -> { 165 | try{ 166 | String fileExtension = nativeLauncher.getExtension(); 167 | if( fileExtension == null || fileExtension.trim().isEmpty() ){ 168 | if( internalUtils.isPlatformWindows() ){ 169 | fileExtension = "exe"; 170 | } 171 | } 172 | Files.copy(windowsLauncherBinary, nativeAppOptions.getOutputBaseFolder().toPath().resolve("windows-x64").resolve(nativeLauncher.getFilename() + "." + fileExtension), StandardCopyOption.REPLACE_EXISTING); 173 | } catch(IOException ex){ 174 | if( nativeAppOptions.isVerbose() ){ 175 | logger.info(null, ex); 176 | } 177 | } 178 | }); 179 | } else { 180 | // assume we are using JDK prior JDK 9 (8,7,...) 181 | // on JDK prior JDK 9, java.home points to the JRE inside the JDK 182 | Path antJfxJar = new File(nativeAppOptions.getJdkPath()).toPath().resolve("lib").resolve("ant-javafx.jar"); 183 | Path antJfxJarinParentFolder = new File(nativeAppOptions.getJdkPath()).toPath().getParent().resolve("lib").resolve("ant-javafx.jar"); 184 | // System.out.println("Checking: " + antJfxJar.toFile().getAbsolutePath()); 185 | // System.out.println("Checking: " + antJfxJarinParentFolder.toFile().getAbsolutePath()); 186 | if( !antJfxJar.toFile().exists() && !antJfxJarinParentFolder.toFile().exists() ){ 187 | // javafx files are not yet installed 188 | throw new MojoExecutionException("Required JavaFX file was not found: ant-javafx.jar, please make sure to have some javafx installed"); 189 | } 190 | System.out.println("Would work on JDK 8 file schema"); 191 | // TODO implement working for JDK8 192 | } 193 | 194 | AtomicReference configurationCreationException = new AtomicReference<>(); 195 | 196 | // TODO check for previous java-app executions for required parameter 197 | List javaAppExecutions = new ArrayList<>(); 198 | File mavenTargetFolder = new File(project.getBuild().getDirectory()); 199 | try{ 200 | Files.walkFileTree(mavenTargetFolder.toPath(), new FileVisitor() { 201 | 202 | boolean enteredFolder = false; 203 | 204 | @Override 205 | public FileVisitResult preVisitDirectory(Path subfolder, BasicFileAttributes attrs) throws IOException { 206 | if( enteredFolder ){ 207 | return FileVisitResult.SKIP_SUBTREE; 208 | } 209 | enteredFolder = true; 210 | return FileVisitResult.CONTINUE; 211 | } 212 | 213 | @Override 214 | public FileVisitResult visitFile(Path sourceFile, BasicFileAttributes attrs) throws IOException { 215 | // do copy, and replace, as the resource might already be existing 216 | if( sourceFile.toFile().getName().startsWith("distbundle.java-app-execution.") ){ 217 | javaAppExecutions.add(sourceFile.toAbsolutePath()); 218 | } 219 | return FileVisitResult.CONTINUE; 220 | } 221 | 222 | @Override 223 | public FileVisitResult visitFileFailed(Path source, IOException ioe) throws IOException { 224 | // fail fast 225 | return FileVisitResult.TERMINATE; 226 | } 227 | 228 | @Override 229 | public FileVisitResult postVisitDirectory(Path source, IOException ioe) throws IOException { 230 | // nothing to do here 231 | return FileVisitResult.CONTINUE; 232 | } 233 | }); 234 | } catch(IOException ioex){ 235 | throw new MojoExecutionException(null, ioex); 236 | } 237 | if( javaAppExecutions.isEmpty() ){ 238 | // TODO check inside internal parameters, as there are no executions 239 | Map internalParameters = Optional.ofNullable(nativeAppOptions.getInternalParameters()).orElseThrow(() -> { 240 | return new MojoFailureException("Could not read from , because it was empty. Please review your plugin-configuration"); 241 | }); 242 | } else { 243 | if( javaAppExecutions.size() == 1 ){ 244 | // TODO get all required information from that single properties-file 245 | try(InputStream execution = Files.newInputStream(javaAppExecutions.get(0))){ 246 | new Properties().load(execution); 247 | } catch(IOException ioex){ 248 | 249 | } 250 | } else { 251 | // TODO check inside internal parameters for execution-id marker, as there are too many executions 252 | Map internalParameters = Optional.ofNullable(nativeAppOptions.getInternalParameters()).orElseThrow(() -> { 253 | return new MojoFailureException("Could not read from , because it was empty. Please review your plugin-configuration"); 254 | }); 255 | } 256 | } 257 | 258 | // TODO create launcher cfg-files 259 | nativeAppOptions.getNativeLaunchers().forEach(nativeLauncher -> { 260 | if( configurationCreationException.get() != null ){ 261 | return; 262 | } 263 | 264 | // check if configuration was provided as normal string 265 | AtomicReference configurationContent = new AtomicReference<>(); 266 | 267 | // first we check configuration file template being set 268 | AtomicReference configurationSourceFileException = new AtomicReference<>(); 269 | File configurationSourceFile = nativeLauncher.getConfigurationFile(); 270 | Optional.ofNullable(nativeLauncher.getConfigurationFile()).ifPresent(configFileTemplate -> { 271 | if( nativeAppOptions.isVerbose() ){ 272 | logger.info(String.format("Reading configuration file for launcher: '%s'", nativeLauncher.getFilename())); 273 | } 274 | try{ 275 | if( !Files.exists(configFileTemplate.toPath(), LinkOption.NOFOLLOW_LINKS) ){ 276 | throw new IOException("Configuration file not found at: " + configFileTemplate.getAbsolutePath()); 277 | } 278 | configurationContent.set(String.join("\n", Files.readAllLines(configFileTemplate.toPath()))); 279 | } catch(IOException ex){ 280 | configurationSourceFileException.set(ex); 281 | } 282 | }); 283 | 284 | if( configurationSourceFileException.get() != null ){ 285 | configurationCreationException.set(new MojoExecutionException(null, configurationSourceFileException.get())); 286 | return; 287 | } 288 | 289 | // when no configuration file template was set, check "configuration" parameter 290 | // TODO find better namen for "configuration" xD 291 | if( configurationContent.get() == null ){ 292 | String xmlConfiguration = nativeLauncher.getConfiguration(); 293 | 294 | // if configuration template still is empty, use internal default one 295 | if( xmlConfiguration == null ){ 296 | if( nativeAppOptions.isVerbose() ){ 297 | logger.info(String.format("Using default configuration for launcher: '%s'", nativeLauncher.getFilename())); 298 | } 299 | // TODO implement cfg-format too (only if older java-version does not support INI) 300 | StringBuilder sb = new StringBuilder(); 301 | try(InputStream resourceAsStream = this.getClass().getResourceAsStream("configurationTemplate.ini")){ 302 | try(BufferedReader reader = new BufferedReader(new InputStreamReader(resourceAsStream))){ 303 | reader.lines().forEachOrdered(line -> sb.append(line).append("\n")); 304 | } 305 | } catch(IOException ioex){ 306 | configurationCreationException.set(new MojoExecutionException("Could not read from default configuration file.", ioex)); 307 | return; 308 | } 309 | configurationContent.set(sb.toString()); 310 | } else { 311 | if( nativeAppOptions.isVerbose() ){ 312 | logger.info(String.format("Using inline configuration for launcher: '%s'", nativeLauncher.getFilename())); 313 | } 314 | // sanitize ugly line-spacings when being specified via xml 315 | String[] xmlConfigurationLines = xmlConfiguration.split("(\r\n)|(\r)|(\n)"); 316 | List sanitizedLines = Arrays.asList(xmlConfigurationLines) 317 | .stream() 318 | .map(line -> line.trim()) 319 | .collect(Collectors.toList()); 320 | configurationContent.set(String.join("\n", sanitizedLines)); 321 | } 322 | } 323 | 324 | // TODO try to read data from previous java-app execution, or search inside internalArguments 325 | System.out.println("Working with TEMPLATE:\n" + configurationContent.get()); 326 | }); 327 | 328 | // copy JRE/runtime 329 | if( nativeAppOptions.isWithJRE() ){ 330 | if( nativeAppOptions.isVerbose() ){ 331 | logger.info("Copying JRE..."); 332 | } 333 | Path runtimeTargetFolder = nativeAppOptions.getOutputBaseFolder().toPath().resolve("windows-x64").resolve("runtime"); 334 | try{ 335 | Files.createDirectories(runtimeTargetFolder); 336 | internalUtils.copyRecursive(new File(nativeAppOptions.getJrePath()).toPath(), runtimeTargetFolder); 337 | } catch(IOException ex){ 338 | if( nativeAppOptions.isVerbose() ){ 339 | logger.error(null, ex); 340 | } 341 | } 342 | } 343 | return null; 344 | } 345 | 346 | @Override 347 | public boolean checkRequirements(NativeAppOptions nativeAppOptions, SharedInternalTools internalUtils, MavenProject project, RepositorySystem repositorySystem, MojoExecution mojoExecution, MavenSession session, Log logger) { 348 | if(nativeAppOptions.isWithJRE()){ 349 | Path javaBinary = new File(nativeAppOptions.getJrePath()).toPath().resolve("bin").resolve("java.exe"); 350 | boolean bitCheckOfLauncherMatching = internalUtils.isWindowsExecutable64bit(javaBinary); 351 | if( !bitCheckOfLauncherMatching ){ 352 | logger.error("Provided JRE does not match expected bit architecture. Detected 32bit JRE instead of 64bit."); 353 | return false; 354 | } 355 | } 356 | return true; 357 | } 358 | 359 | @Override 360 | public boolean creatableOnBuildsystem(OS os) { 361 | return os == OS.WINDOWS; 362 | } 363 | 364 | @Override 365 | public String getBundlerIdentifier() { 366 | return "oracle-native-launcher"; 367 | } 368 | 369 | @Override 370 | public OS getDistributionTargetOS() { 371 | return OS.WINDOWS; 372 | } 373 | 374 | @Override 375 | public void printHelp() { 376 | return; 377 | } 378 | 379 | } 380 | -------------------------------------------------------------------------------- /maven-plugin/src/main/java/de/dynamicfiles/projects/maven/distributionbundleplugin/mojo/CreateNativeAppBundle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Danny Althoff 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.dynamicfiles.projects.maven.distributionbundleplugin.mojo; 17 | 18 | import de.dynamicfiles.projects.maven.distributionbundleplugin.InternalUtils; 19 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.NativeAppOptions; 20 | import de.dynamicfiles.projects.maven.distributionbundleplugin.api.NativeLauncher; 21 | import de.dynamicfiles.projects.maven.distributionbundleplugin.spi.NativeAppBundler; 22 | import java.io.File; 23 | import java.io.IOException; 24 | import java.net.MalformedURLException; 25 | import java.net.URL; 26 | import java.net.URLClassLoader; 27 | import java.nio.file.Files; 28 | import java.nio.file.LinkOption; 29 | import java.util.ArrayList; 30 | import java.util.HashMap; 31 | import java.util.List; 32 | import java.util.Map; 33 | import java.util.Optional; 34 | import java.util.ServiceLoader; 35 | import java.util.Set; 36 | import java.util.concurrent.atomic.AtomicBoolean; 37 | import java.util.concurrent.atomic.AtomicReference; 38 | import java.util.stream.Collectors; 39 | import org.apache.maven.artifact.Artifact; 40 | import org.apache.maven.artifact.InvalidRepositoryException; 41 | import org.apache.maven.artifact.resolver.ArtifactResolutionRequest; 42 | import org.apache.maven.artifact.resolver.ArtifactResolutionResult; 43 | import org.apache.maven.execution.MavenSession; 44 | import org.apache.maven.plugin.AbstractMojo; 45 | import org.apache.maven.plugin.AbstractMojoExecutionException; 46 | import org.apache.maven.plugin.MojoExecution; 47 | import org.apache.maven.plugin.MojoExecutionException; 48 | import org.apache.maven.plugin.MojoFailureException; 49 | import org.apache.maven.plugins.annotations.Component; 50 | import org.apache.maven.plugins.annotations.Mojo; 51 | import org.apache.maven.plugins.annotations.Parameter; 52 | import org.apache.maven.project.MavenProject; 53 | import org.apache.maven.repository.RepositorySystem; 54 | 55 | /** 56 | * This MOJO creates an native executable java application bundle which can get wrapped in some ZIP-file. As input-file the previous generated 57 | * java-app bundle is used in order to it distributable using native launchers. 58 | * 59 | * As a short term goal this re-uses the files provided by JDK8-10/OpenJFX. 60 | * 61 | * @author Danny Althoff 62 | */ 63 | @Mojo(name = "native-app") 64 | public class CreateNativeAppBundle extends AbstractMojo { 65 | 66 | @Parameter(defaultValue = "${project}", readonly = true) 67 | private MavenProject project; 68 | 69 | @Component 70 | private RepositorySystem repositorySystem; 71 | 72 | @Parameter(defaultValue = "${mojoExecution}", readonly = true) 73 | private MojoExecution mojoExecution; 74 | 75 | @Parameter(defaultValue = "${session}", readonly = true) 76 | private MavenSession session; 77 | 78 | /** 79 | * Enable to see some status messages. 80 | */ 81 | @Parameter(defaultValue = "false") 82 | private boolean verbose; 83 | 84 | /** 85 | * Source folder to pick up the application. It's not required that this application has to be created by this 86 | * plugin, but expects a special file/folder layout. 87 | */ 88 | @Parameter(defaultValue = "${project.build.directory}/distbundle/java-app", property = "distbundle.nativeapp.sourceFolder") 89 | private File sourceFolder; 90 | 91 | @Parameter(defaultValue = "${project.build.directory}/distbundle/native-app", property = "distbundle.nativeapp.outputBaseFolder") 92 | private File outputBaseFolder; 93 | 94 | /** 95 | * Some tasks require a special space to extract or manipulate files. To change the location, 96 | * just set this parameter to your wanted location. 97 | */ 98 | @Parameter(defaultValue = "${project.build.directory}/distbundle-tmp", property = "distbundle.nativeapp.tempWorkfolder") 99 | private File tempWorkfolder; 100 | 101 | /** 102 | * When creating a native bundle, it sometimes is needed to clean the output-folder first. To speedup the process, the output-folder 103 | * will not be cleaned, but it might result in files being present after it got deleted from the source-folder. Set this to true to 104 | * recursivly delete the output-folder on each execution. 105 | */ 106 | @Parameter(defaultValue = "false", property = "distbundle.nativeapp.cleanupOutputFolder") 107 | private boolean cleanupOutputFolder; 108 | 109 | /** 110 | * In case your have a special JDK to be used for bundling, please specify this here. Expects some 111 | * extracted/installed JDK (whether its OracleJDK or OpenJDK+OpenJFX). 112 | */ 113 | @Parameter(defaultValue = "${java.home}") 114 | private String jdkPath; 115 | 116 | /** 117 | * If you want no JRE being bundled with your application, just set this parameter to "false". 118 | */ 119 | @Parameter(defaultValue = "true") 120 | private boolean withJRE; 121 | 122 | /** 123 | * To bundle your application with the JRE, you have to set this parameter. When having JDK9+ the location can 124 | * be set to "${java.home}/../jre-${java.version}", on JDK8 the JRE inside the JDK will get used (like the javapackager 125 | * and the javafx-maven-plugin before). 126 | */ 127 | @Parameter 128 | private String jrePath; 129 | 130 | /** 131 | * In case you want to have multiple native launchers, please create them here, each with a different 132 | * appName (otherwise it'll be revoked to work on). 133 | * If nothing specified, the application will be build using the project artifact finalname as filename. 134 | */ 135 | @Parameter 136 | private List nativeLaunchers; 137 | 138 | /** 139 | * GAV 140 | * de.dynamicfiles.projects.maven.distributionbundleplugin.bundler:native-app-windows-x64:1.0.0-SNAPSHOT 141 | */ 142 | @Parameter(defaultValue = "") 143 | private String bundlerSource; 144 | 145 | /** 146 | * Uses latest version of bundler per default. To avoid this, fixate the version here. 147 | * 148 | * 1.0.0-SNAPSHOT 149 | */ 150 | @Parameter(defaultValue = "") 151 | private String overrideBundlerSourceVersion; 152 | 153 | /** 154 | * A bundler source might contain multiple bundlers, which are identified by some internal ID. 155 | * 156 | * oracle-native-launcher 157 | */ 158 | @Parameter(defaultValue = "") 159 | private String bundlerFlavor; 160 | 161 | /** 162 | * Per default the OS of the build-system is used. 163 | * 164 | * linux 165 | * mac 166 | * windows 167 | */ 168 | @Parameter(defaultValue = "") 169 | private String clientOS; 170 | 171 | /** 172 | * Per default the cpu architecture of the build-system is used. 173 | * 174 | * x32 175 | * x64 176 | */ 177 | @Parameter(defaultValue = "") 178 | private String clientArch; 179 | 180 | /** 181 | * Some bundlers might have special configuration options, these are set via a simple <key>value</key> string entry. 182 | * As these options are highly unique to each bundler, please look into the corresponding documentation. 183 | */ 184 | @Parameter 185 | private Map internalParameters = new HashMap<>(); 186 | 187 | private final InternalUtils internalUtils = new InternalUtils(); 188 | 189 | private final String HARDCODED_DEFAULT_BUNDLER_GROUPID = "de.dynamicfiles.projects.maven.distributionbundleplugin.bundler"; 190 | private final String HARDCODED_DEFAULT_BUNDLER_ARTIFACTID_PREFIX = "native-app-"; 191 | 192 | @Override 193 | public void execute() throws MojoExecutionException, MojoFailureException { 194 | // first check if there is something to process on 195 | if( !sourceFolder.exists() || sourceFolder.list().length == 0 ){ 196 | throw new MojoExecutionException("No resources found to work on. Make sure to call 'distbundle:java-app' first."); 197 | } 198 | 199 | if( verbose ){ 200 | getLog().info("Prepare target area: " + outputBaseFolder.toString()); 201 | } 202 | 203 | if( outputBaseFolder.exists() && cleanupOutputFolder ){ 204 | try{ 205 | if( verbose ){ 206 | getLog().info("Deleting recursively: " + outputBaseFolder.toString()); 207 | } 208 | internalUtils.deleteRecursive(outputBaseFolder.toPath()); 209 | } catch(IOException ex){ 210 | throw new MojoFailureException("Not possible to cleanup output folder: " + outputBaseFolder.getAbsolutePath(), ex); 211 | } 212 | } 213 | 214 | if( !outputBaseFolder.exists() && !outputBaseFolder.mkdirs() ){ 215 | throw new MojoFailureException("Not possible to create output folder: " + outputBaseFolder.getAbsolutePath()); 216 | } 217 | 218 | if( !tempWorkfolder.exists() && !tempWorkfolder.mkdirs() ){ 219 | throw new MojoFailureException("Not possible to create temporary working folder: " + tempWorkfolder.getAbsolutePath()); 220 | } 221 | 222 | if( withJRE ){ 223 | if( jrePath == null || jrePath.trim().isEmpty() ){ 224 | if( verbose ){ 225 | getLog().info("JRE was not set, trying to autodetect..."); 226 | } 227 | // detect jmods-folder in order to detect jdk9+ 228 | boolean isUsingJmodFiles = Files.exists(new File(jdkPath).toPath().resolve("jmods"), LinkOption.NOFOLLOW_LINKS); 229 | if( isUsingJmodFiles ){ 230 | if( verbose ){ 231 | getLog().info("Found JDK9+ layout."); 232 | } 233 | // JDK9+ 234 | jrePath = System.getProperty("java.home") + "/../jre-" + System.getProperty("java.version"); 235 | } else { 236 | if( verbose ){ 237 | getLog().info("Found JDK8 layout."); 238 | } 239 | // JDK8 240 | // please be aware that java.home does NOT equal to JAVA_HOME, this is an often 241 | // misinterpreted system-property, it points to the JRE inside the JDK 242 | jrePath = System.getProperty("java.home"); 243 | } 244 | } 245 | File jre = new File(jrePath); 246 | jrePath = jre.toPath().normalize().toAbsolutePath().toFile().getAbsolutePath(); 247 | if( !jre.exists() ){ 248 | throw new MojoFailureException("Could not find JRE at location: " + jrePath); 249 | } 250 | } 251 | 252 | if( verbose ){ 253 | getLog().info("Checking and sanitizing native launcher configuration..."); 254 | } 255 | 256 | // prepare native launchers list 257 | if( nativeLaunchers == null ){ 258 | nativeLaunchers = new ArrayList<>(); 259 | } 260 | if( nativeLaunchers.isEmpty() ){ 261 | if( verbose ){ 262 | getLog().info("Adding default native launcher entry..."); 263 | } 264 | 265 | NativeLauncher defaultLauncher = new NativeLauncher(); 266 | defaultLauncher.setFilename(project.getBuild().getFinalName()); 267 | if( internalUtils.isPlatformWindows() ){ 268 | defaultLauncher.setExtension("exe"); 269 | } 270 | nativeLaunchers.add(defaultLauncher); 271 | } 272 | 273 | if( verbose ){ 274 | getLog().info("Constructing bundler source maven coordinates..."); 275 | } 276 | 277 | // download bundler-source-artifact (might contain multiple bundlers) 278 | // to get this artifact, we have to create our source-GAV 279 | AtomicReference bundlerSourceToUse = new AtomicReference<>(); 280 | Optional.ofNullable(bundlerSource).ifPresent(configuredBundlerSource -> { 281 | if( configuredBundlerSource.trim().isEmpty() ){ 282 | return; 283 | } 284 | 285 | // check if it contains GAV 286 | if( configuredBundlerSource.split(":").length <= 2 ){ 287 | getLog().warn("Provided bundler source did not contain GAV format, using default bundler source artifact. Please check your plugin-configuration."); 288 | return; 289 | } 290 | 291 | // developer did provide some GAV-reachable artifact 292 | bundlerSourceToUse.set(configuredBundlerSource.trim()); 293 | }); 294 | 295 | // used did not set custom source, so let's use the "default one" 296 | if( bundlerSourceToUse.get() == null ){ 297 | if( verbose ){ 298 | getLog().info("Using default bundler source artifact coordinates."); 299 | } 300 | 301 | // check targeted clientOS/-Arch for generating artifact-id 302 | AtomicReference clientOSToUse = new AtomicReference<>(); 303 | Optional.ofNullable(clientOS).ifPresent(configuredClientOS -> { 304 | if( configuredClientOS.trim().isEmpty() ){ 305 | return; 306 | } 307 | 308 | // developer selected clientOS 309 | clientOSToUse.set(configuredClientOS.trim()); 310 | }); 311 | 312 | // user did not set custom clientOS, so let's use the "default one" 313 | if( clientOSToUse.get() == null ){ 314 | if( internalUtils.isPlatformWindows() ){ 315 | clientOSToUse.set("windows"); 316 | } 317 | if( internalUtils.isPlatformLinux() ){ 318 | clientOSToUse.set("linux"); 319 | } 320 | if( internalUtils.isPlatformMac() ){ 321 | clientOSToUse.set("mac"); 322 | } 323 | } 324 | 325 | AtomicReference clientArchToUse = new AtomicReference<>(); 326 | Optional.ofNullable(clientArch).ifPresent(configuredClientArch -> { 327 | if( configuredClientArch.trim().isEmpty() ){ 328 | return; 329 | } 330 | 331 | // developer selected clientArch 332 | clientArchToUse.set(configuredClientArch.trim()); 333 | }); 334 | 335 | // user did not set custom clientArch, so let's use the "default one" 336 | if( clientArchToUse.get() == null ){ 337 | // even when this might seem like "get bit of operating system", it seems to be the architecture of the running jdk 338 | if( System.getProperty("os.arch").contains("64") ){ 339 | clientArchToUse.set("x64"); 340 | } else { 341 | clientArchToUse.set("x86"); 342 | } 343 | } 344 | 345 | bundlerSourceToUse.set(HARDCODED_DEFAULT_BUNDLER_GROUPID + ":" + HARDCODED_DEFAULT_BUNDLER_ARTIFACTID_PREFIX + clientOSToUse.get() + "-" + clientArchToUse.get() + ":" + mojoExecution.getPlugin().getVersion()); 346 | } 347 | 348 | String bundlerSourceGAV = bundlerSourceToUse.get(); 349 | String[] bundlerSourceParts = bundlerSourceGAV.split(":"); 350 | 351 | Artifact bundlerSourceArtifact = null; 352 | if( bundlerSourceParts.length == 3 ){ 353 | // GAV 354 | bundlerSourceArtifact = repositorySystem.createArtifact(bundlerSourceParts[0], bundlerSourceParts[1], Optional.ofNullable(overrideBundlerSourceVersion).orElse(bundlerSourceParts[2]), "jar"); 355 | } 356 | if( bundlerSourceParts.length == 4 ){ 357 | // GAV + classifier 358 | bundlerSourceArtifact = repositorySystem.createArtifact(bundlerSourceParts[0], bundlerSourceParts[1], Optional.ofNullable(overrideBundlerSourceVersion).orElse(bundlerSourceParts[2]), "jar", bundlerSourceParts[3]); 359 | } 360 | 361 | if( bundlerSourceArtifact == null ){ 362 | throw new MojoExecutionException("Provided bundlerSource did not contain the requested GAV-format. Please check your configuration."); 363 | } 364 | 365 | if( verbose ){ 366 | getLog().info(String.format("Using GAV for bundler source artifact: %s", bundlerSourceToUse.get())); 367 | } 368 | 369 | // try to resolve this artifact 370 | ArtifactResolutionRequest request = new ArtifactResolutionRequest(); 371 | 372 | request.setArtifact(bundlerSourceArtifact); 373 | try{ 374 | request.setLocalRepository(repositorySystem.createDefaultLocalRepository()); 375 | } catch(InvalidRepositoryException ire){ 376 | throw new MojoExecutionException("Got exception while creating local repository reference.", ire); 377 | } 378 | request.setRemoteRepositories(project.getRemoteArtifactRepositories()); 379 | 380 | if( session.isOffline() ){ 381 | if( verbose ){ 382 | getLog().info("Activating OFFLINE search"); 383 | } 384 | 385 | request.setOffline(true); 386 | } 387 | 388 | if( verbose ){ 389 | getLog().info("Starting bundler source artifact resolution..."); 390 | } 391 | 392 | ArtifactResolutionResult result = repositorySystem.resolve(request); 393 | 394 | if( !result.isSuccess() ){ 395 | throw new MojoExecutionException("Could not resolve bundler source, got some exceptions (" + result.hasExceptions() + "), here is the last one:", result.getExceptions().get(result.getExceptions().size() - 1)); 396 | } 397 | 398 | Set artifactUrls = result.getArtifacts() 399 | .stream() 400 | .map(artifact -> { 401 | return artifact.getFile().toURI(); 402 | }) 403 | .map(uri -> { 404 | try{ 405 | return uri.toURL(); 406 | } catch(MalformedURLException ex){ 407 | // NO-OP stupid java api 408 | } 409 | return null; 410 | }) 411 | .filter(entry -> entry != null) 412 | .collect(Collectors.toSet()); 413 | 414 | if( verbose ){ 415 | getLog().info("Creating temporary classloader for found bundler source artifact..."); 416 | } 417 | 418 | // create our own classloader for easier isolation 419 | URLClassLoader cl = new URLClassLoader( 420 | artifactUrls.toArray(new URL[0]), 421 | Thread.currentThread().getContextClassLoader() 422 | ); 423 | 424 | AtomicBoolean didRun = new AtomicBoolean(false); 425 | AtomicReference innerException = new AtomicReference<>(); 426 | 427 | AtomicBoolean hasSpecialFlavorRequest = new AtomicBoolean(false); 428 | Optional.ofNullable(bundlerFlavor).ifPresent(flavor -> { 429 | if( !flavor.trim().isEmpty() ){ 430 | hasSpecialFlavorRequest.set(true); 431 | } 432 | }); 433 | 434 | if( verbose ){ 435 | getLog().info("Searching for NativeAppBundler service implementations..."); 436 | } 437 | 438 | ServiceLoader nativeAppBundlerServices = ServiceLoader.load(NativeAppBundler.class, cl); 439 | 440 | nativeAppBundlerServices.iterator().forEachRemaining(appBundler -> { 441 | // first found native app bundler wins 442 | // skip if any exception was thrown 443 | if( didRun.get() || innerException.get() != null ){ 444 | return; 445 | } 446 | 447 | if( hasSpecialFlavorRequest.get() ){ 448 | // if special bundler flavor was configured, skip each non-matching 449 | if( !bundlerFlavor.trim().equalsIgnoreCase(appBundler.getBundlerIdentifier()) ){ 450 | if( verbose ){ 451 | getLog().info("Found bundler did not match requested id: " + appBundler.getBundlerIdentifier()); 452 | } 453 | 454 | return; 455 | } 456 | } 457 | 458 | if( verbose ){ 459 | getLog().info("Using bundler with id: " + appBundler.getBundlerIdentifier()); 460 | } 461 | 462 | try{ 463 | if( verbose ){ 464 | getLog().info("Running bundler requirements checks..."); 465 | } 466 | 467 | NativeAppOptions nativeAppOptions = new NativeAppOptions(); 468 | 469 | nativeAppOptions.setInternalParameters(internalParameters); 470 | nativeAppOptions.setJdkPath(jdkPath); 471 | nativeAppOptions.setJrePath(jrePath); 472 | nativeAppOptions.setNativeLaunchers(nativeLaunchers); 473 | nativeAppOptions.setOutputBaseFolder(outputBaseFolder); 474 | nativeAppOptions.setSourceFolder(sourceFolder); 475 | nativeAppOptions.setTempWorkfolder(tempWorkfolder); 476 | nativeAppOptions.setVerbose(verbose); 477 | nativeAppOptions.setWithJRE(withJRE); 478 | 479 | appBundler.checkRequirements(nativeAppOptions, internalUtils, project, repositorySystem, mojoExecution, session, getLog()); 480 | 481 | if( verbose ){ 482 | getLog().info("Running creation of native app bundle..."); 483 | } 484 | 485 | // here we have a "valid" bundler, so call it 486 | File bundlerOutput = appBundler.bundleApp(nativeAppOptions, internalUtils, project, repositorySystem, mojoExecution, session, getLog()); 487 | } catch(MojoFailureException | MojoExecutionException ex){ 488 | // pass exception to outer world 489 | innerException.set(ex); 490 | } 491 | didRun.set(true); 492 | }); 493 | 494 | if( innerException.get() != null ){ 495 | AbstractMojoExecutionException thrownInnerException = innerException.get(); 496 | throw new MojoFailureException("There was a problem while creating the native app bundle, please check your build log.", thrownInnerException); 497 | } 498 | 499 | try{ 500 | cl.close(); 501 | } catch(IOException ex){ 502 | // NO-OP 503 | } 504 | if( !didRun.get() ){ 505 | throw new MojoFailureException("No bundler found to build with, please check your plugin-configuration."); 506 | } 507 | } 508 | } 509 | --------------------------------------------------------------------------------