├── README.md ├── expose.gif ├── pom.xml └── src └── main └── java └── paroxayte └── SelfExec.java /README.md: -------------------------------------------------------------------------------- 1 | # selfexec-maven-plugin 2 | 3 | A maven plugin that allows jar files to be executed transparently (no java -jar ...). OS X and Linux systems are supported, Windows may be usable with a WSL. This maven plugin appends an sh script to the head of a certain jar in the ${project.build.directory} allowing it to be executed from a CLI without ceremony. The self-exec plugin may also be used to embed flags and user defined run commands. 4 |
5 | 6 | ## Usage 7 | *Making a self executing jar from a Hello World project and running* 8 | ![](expose.gif?raw=true "simple") 9 | 10 | ## Installation Instructions 11 | 12 | 13 | 14 | jitpack.io 15 | https://jitpack.io 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | com.github.paroxayte 24 | selfexec-maven-plugin 25 | v1.5.1 26 | 27 | 28 | com.github.paroxayte 29 | selfexec-maven-plugin 30 | v1.5.1 31 | 32 | 33 | ### *Optional* 34 | To making running this plugin from the command line significantly shorter, a configuration can be added to the maven settings.xml file. The is located in your maven home repository (eg: ~/.m2/repository). If a settings.xml does not exist create one and add the following: 35 | 36 | 37 | .... 38 | 39 | com.github.paroxayte 40 | 41 | 42 | After this added you will be able to invoke the plugin with `mvn selfexec:selfexec` 43 | 44 | ## Configurations 45 | 46 | This plugin has the following public properties: 47 | 48 | * **jarName:** Represents the jarFile to be made self executable. Default value - `${project.artifactId}-${project.version}` 49 | 50 | * **finalName:** Determines the name of the generated self-executing jar. If it is the same as another file name in the output directory, it will overwrite that file. 51 | 52 | * **jarLoc:** The directory which contains the target jarFile. Default value -`${project.build.directory}` 53 | 54 | * **flags:** The command to embed in to the jar file. Default value - `java -jar $0 \"$@\"` 55 | 56 | * **shebang** The shebang of the embedded script. Default value - `#!/bin/sh` 57 | 58 | The single goal of this plugin, **selfexec** simply creates a new file which is a self executing version of the provided jar. 59 | 60 | ### Example configuration 61 | 62 | 63 | 64 | 65 | 66 | com.github.paroxayte 67 | selfexec-maven-plugin 68 | v1.5.1 69 | 70 | 71 | com.github.paroxayte 72 | selfexec-maven-plugin 73 | v1.5.1 74 | 75 | foo 76 | 77 | 78 | 79 | install 80 | 81 | selfexec 82 | 83 | 84 | 85 | 86 | 87 | If you use a custom name on your jar, it may be desirable to set a property to keep you finalName and jarName linked since they must be the same. EG: 88 | 89 | 90 | example 91 | 92 | ... 93 | ${buildName} 94 | ... 95 | ${buildName} 96 | 97 | This plugin may also be run from the CLI in a maven project directory. `mvn selfexec:selfexec` 98 | 99 |
100 | 101 | -------------------------------------------------------------------------------- /expose.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fireflowerr/selfexec-maven-plugin/60eb5b141d30353dfe7bec45acc4cce6dc2b4d41/expose.gif -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.github.paroxayte 5 | selfexec-maven-plugin 6 | maven-plugin 7 | v1.5.1 8 | selfexec-maven-plugin 9 | https://github.com/paroxayte/selfexec-maven-plugin 10 | 11 | 12 | UTF-8 13 | 1.8 14 | 1.8 15 | 16 | 17 | 18 | 19 | org.apache.maven 20 | maven-plugin-api 21 | 3.5.4 22 | 23 | 24 | org.apache.maven.plugin-tools 25 | maven-plugin-annotations 26 | 3.5.2 27 | compile 28 | 29 | 30 | 31 | 32 | 33 | 34 | org.apache.maven.plugins 35 | maven-plugin-plugin 36 | 3.5.2 37 | 38 | selfexec 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/main/java/paroxayte/SelfExec.java: -------------------------------------------------------------------------------- 1 | package paroxayte; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.BufferedOutputStream; 5 | import java.io.DataInputStream; 6 | import java.io.DataOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.OutputStream; 10 | import java.io.OutputStreamWriter; 11 | import java.io.PrintWriter; 12 | import java.nio.charset.StandardCharsets; 13 | import java.nio.file.FileSystems; 14 | import java.nio.file.Files; 15 | import java.nio.file.Path; 16 | import java.nio.file.StandardOpenOption; 17 | import java.nio.file.attribute.PosixFilePermissions; 18 | import org.apache.maven.plugin.AbstractMojo; 19 | import org.apache.maven.plugin.MojoExecutionException; 20 | import org.apache.maven.plugins.annotations.Mojo; 21 | import org.apache.maven.plugins.annotations.Parameter; 22 | 23 | 24 | @Mojo(name = "selfexec") 25 | public class SelfExec extends AbstractMojo { 26 | 27 | // The name of the jar to be made self executing. 28 | @Parameter(property = "jarName", defaultValue = "${project.artifactId}-${project.version}") 29 | private String jarName; 30 | 31 | // Determines the name of the outputed selfexec jar file. Default value is jarName without .jar extension 32 | @Parameter(property = "finalName") 33 | private String finalName; 34 | 35 | //The directory to look for the jar file in. 36 | @Parameter(property = "jarLoc", defaultValue = "${project.build.directory}") 37 | private String buildDir; 38 | 39 | //The command to run the jar with. 40 | @Parameter(property = "flags", defaultValue = "java -jar $0 \"$@\"") 41 | private String flags; 42 | 43 | //The shebang to use (change to use a different bash shell) 44 | @Parameter(property = "shebang", defaultValue = "#!/bin/sh") 45 | private String shebang; 46 | 47 | public void execute() throws MojoExecutionException { 48 | if(!jarName.matches(".+\\.jar$")) { 49 | jarName += ".jar"; 50 | } 51 | 52 | if(finalName == null) { 53 | finalName = jarName.substring(0, jarName.length() - 4); 54 | } 55 | 56 | Path finalNamePath = FileSystems.getDefault().getPath(buildDir, finalName); 57 | Path jarFile = FileSystems.getDefault().getPath(buildDir, jarName); 58 | 59 | if (Files.exists(jarFile)) { 60 | 61 | try(InputStream baseIn = Files.newInputStream(jarFile, StandardOpenOption.READ); OutputStream baseOut = Files.newOutputStream(finalNamePath, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);) { 62 | 63 | // Begin constructing self executing jar 64 | PrintWriter scriptWrite = new PrintWriter(new OutputStreamWriter(baseOut, StandardCharsets.UTF_8), true); 65 | scriptWrite.println(shebang); 66 | scriptWrite.println("\n\n"); 67 | scriptWrite.println("exec " + flags); 68 | scriptWrite.println("\n\n\n\n"); 69 | 70 | // Build a execute script and append jar to it 71 | DataInputStream readIn = new DataInputStream(new BufferedInputStream(baseIn)); 72 | DataOutputStream writeOut = new DataOutputStream(new BufferedOutputStream(baseOut)); 73 | byte[] bufStore = new byte[readIn.available()]; 74 | int bytesRead; 75 | while((bytesRead = readIn.read(bufStore)) > 0) { 76 | writeOut.write(bufStore, 0, bytesRead); 77 | } 78 | writeOut.flush(); 79 | 80 | } catch(IOException e) { 81 | e.printStackTrace(); 82 | } finally { 83 | try { 84 | Files.setPosixFilePermissions(finalNamePath, PosixFilePermissions.fromString("rwxr-xr-x")); 85 | } catch(IOException e) { 86 | throw new RuntimeException("Failed to set executable permissions...", e); 87 | } 88 | } 89 | 90 | } else { 91 | throw new MojoExecutionException(jarName + " not found in build output directory"); 92 | } 93 | 94 | } 95 | 96 | } --------------------------------------------------------------------------------