maven zip uber-jar and shell script - shell

I would like maven to combine an uber-jar created by the shade-plugin and a shell script from the all_files directory.
The project structure looks like this:
all_files/
mvn_script.sh
projB-shaded.jar
maven_project/
guide/
parent-pom.xml
projA/
pom.xml
projB/
pom.xml
The jar is produced by projectB's pom file and then placed into the outtermost folder to be ready to be zipped with the shell script. The reason is so that the shell script can call the jar file to execute the project.
I want other programmers to be able to easily unzip the file and run the shell script without worry. And I also need to have maven package the script and jar together. I'm not sure exactly how to implement that within the shaded plugin.
Note: I do not want to use assembly-plugin because it doesn't package dependent jars well.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<outputFile>../../guide/${project.artifactId}-${project.version}-shaded.jar</outputFile>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>projB.classB</Main-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>

You don't want to use the maven-assembly-plugin for creating the uber-jar. But you will want to use it to create that ZIP.
Currently, your maven-shade-plugin is bound to the package phase. You could shift that execution to the prepare-package phase (since it actually prepares your final packaging) add an execution of the maven-assembly-plugin bound to the package phase. Your assembly would create a ZIP based on the shaded JAR (which will exist since the shade plugin will have been executed) and the shell script.
A sample descriptor would be the following:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>your-id</id>
<formats>
<format>zip</format>
</formats>
<files>
<file>
<source>${project.build.directory}/projB-shaded.jar</source>
<outputDirectory>/</outputDirectory>
</file>
<file>
<source>/path/to/mvn_script.sh</source>
<outputDirectory>/</outputDirectory>
</file>
</files>
</assembly>
with the following POM configuration:
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<!-- current configuration -->
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>assemble</id>
<goals>
<goal>single</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptors>
<descriptor>/path/to/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
The typical location for the assembly descritor is under src/assembly as per the Maven standard directory layout.

Related

Maven build lifecycle phase synchronization across modules

I have a maven project with a reactor and a couple of modules, most of which are being packed as war. The order in which they are specified in the reactor / root pom.xml defines the order in which they are built.
pom.xml
....
<module>library1</module>
<module>library2</module>
<module>webapp1</module><!--war-->
<module>webapp2</module><!--war-->
<module>blackduck-scan</module><!-- create file to be placed into webapp2 post-build but pre-packaging of webapp2 -->
...
The last module, purposely, is destined to simply run an executable in the prepare-package phase. More precisely a blackduck license scanner, which itself eventually produces the license notice file which is then placed into the /webapp folder of one of the web applications to be displayed after deployment.
The idea is what this notice file is being placed after compilation of the applications but before packaging these as WAR artifacts to have it included in the current delivery of our pipeline without re-building just for the sake of re-packaging.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<executable>java</executable>
<workingDirectory>.</workingDirectory>
<arguments>
<argument>-jar</argument>
<argument>synopsys-detect-8.4.0.jar</argument>
</arguments>
...
</configuration>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
<phase>prepare-package</phase>
</execution>
</executions>
</plugin>
I've tried two options to achieve this without success.
a) Adding the plugin/goal to the reactor pom.xml leads to the goal being executed first as soon as the target phase is prepare-package and thus may lead to incomplete scan results while the actual project has not yet been built.
b) Adding then plugin/goal as a module as described above puts the execution at the end of the chain, however, packaging of the webapps has already been concluded.
c) The third (arguably working) but less elegant approach would be to split this into two separate maven calls:
mvn clean install && mvn package
I see that modules are build in sequence and for good reason. However, is there any method to "synchronize" build phases such that each phase is started only after the previous phase has been completed for all modules? Effectively to simply call, all included:
mvn clean install
I believe the option is:
disable war creation and run exploded goal instead
use maven-assembly-plugin to pack target war
inject execution of blackduck between maven-war-plugin and maven-assembly-plugin
smth. like:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<executions>
<execution>
<!-- disabling building war -->
<id>default-war</id>
<phase>none</phase>
</execution>
<execution>
<id>exploded</id>
<phase>prepare-package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- blackduck execution here -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptors>
<descriptor>war-assembly.xml</descriptor>
</descriptors>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</plugin>
war-assembly.xml:
<assembly>
<id>war</id>
<formats>
<format>war</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}/${project.build.finalName}</directory>
<outputDirectory>.</outputDirectory>
<includes>
<include>/**/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>

Create a tar with maven generated jar with dependenceis and few other files

I'm new to maven and its interesting subject to learn.
Succeed to create a jar with dependencies, using:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</configuration>
</plugin>
Now, i have to include few shell scripts and generated jar to a tar.
To achieve this, i ve tried the following way:
Added
<descriptors>
<descriptor>hadoop-job.xml</descriptor>
</descriptors>
to the above script.
In hadoop-job.xml i'm including required files into tar.
The problem is tar is generated first and says no *.jar found in target.
Is there a way to schedule jar creation first and tar next, since both the configurations reside in assembly plugin.
OR
Is there a command to execute and generate a jar first and then a command to generate a tar ?
By the way i'm executing mvn clean assembly:assembly -Dbinary=true.
Help me to resolve. Thanks.
Here is an example of assembly building the jar-with-dependencies and after that a tar that includes this jar-with-dependencies (built by the maven-assembly-plugin just before). In the tar I also includes the shell script files in .sh from the folder src/main/bin.
First, the plugin configuration :
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<id>jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorId>jar-with-dependencies</descriptorId>
</descriptorRefs>
</configuration>
</execution>
<execution>
<id>all</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/assembly/all.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.directory}/assembly/</outputDirectory>
</configuration>
</plugin>
The order of the executions is important because if I want to include the jar-with-dependencies into my tar I need to have it built before.
I put all the assemblies in the same folder, that's why I have a global configuration tag additionally to the configuration tag of the executions
And then the content of my assembly file all.xml :
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>all</id>
<formats>
<format>tar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>**/*.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>src/main/bin</directory>
<outputDirectory>bin</outputDirectory>
<fileMode>755</fileMode>
</fileSet>
</fileSets>
</assembly>
The includeBaseDirectory is here to avoid my tar containing the root folder with the name of the project with the version.
If you don't specify the outputDirectory tags, the folder structure into your archive will begin from the root of the project, for example it will include your jar with the path target/your-project-1.0-SNAPSHOT.jar.
EDIT : The plugin configuration that I did before could be simplified with just the following :
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<id>jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorId>jar-with-dependencies</descriptorId>
<descriptors>
<descriptor>src/assembly/all.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.directory}/assembly/</outputDirectory>
</configuration>
</plugin>
The reason is because in the maven-assembly-plugin the descriptorId is read before the descriptors so that's good for our case but if not, we would need two executions as done higher with care about the order.
The same attention have to be done for the order of the descriptors, they are performed in the reading order (it can seems logic but I think it might be useful to indicate it).

Create a zip file and add it to a war file with maven

I have some example RESTful client projects that go along with a RESTful Java web service I am working on. Basically, these projects should not be built but instead zipped up and included in the war file so that they will be available as static resources when the war file is deployed. This makes it easy to update the example clients along with the actual Java web service and guarantee that they are deployed together.
I've been able to use the maven assembly plugin to create a zip file but that stage executes after the war stage. I haven't been able to figure out the maven incantation needed to create the zip file then add it to the war file.
Here is what I have so far, but it only does about half the job. Also, I need to move the ExampleProject directory so the unzipped files don't go into the final war file.
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptor>src/assembly/AssembleExamples.xml</descriptor>
<finalName>examples.zip</finalName>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
AssembleExamples.xml
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>bin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/WebContent/docs/</directory>
<outputDirectory/>
<includes>
<include>ExampleProject/pom.xml</include>
<include>ExampleProject/src/**</include>
</includes>
</fileSet>
</fileSets>
</assembly>
Two of the plugins maven-war-plugin and maven-assembly-plugin are required to be executed in the same phase, package. First, maven-assembly-plugin and then maven-war-plugin. You need to add the plugins in the following order to make sure that they run in same phase and correct order:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.1</version>
<executions>
<execution>
<id>prepare-war</id>
<phase>package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptor>src/assembly/AssembleExamples.xml</descriptor>
<finalName>examples.zip</finalName>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
You can generate the war using mvn package.
Here is how I ended up doing it.
Thanks to Mithun I realized that there are two ways to configure the war plugin and the way I was doing it was not appropriate for my situation.
This is what I added to my pom file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<configuration>
<descriptor>src/assembly/AssembleJavaExample.xml</descriptor>
<finalName>myexample</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}/${project.build.finalName}/docs</outputDirectory>
</configuration>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>true</failOnMissingWebXml>
<warName>mywar</warName>
<warSourceExcludes>docs/myexample/**</warSourceExcludes>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
</execution>
</executions>
</plugin>
The assembly plugin had to go first so it would execute before the war plugin. The assembly plugin creates the zip file and places it in the directory that the war plugin uses to create the war file (the outputDirectory configuration). I then had to exclude the example sources from being included in the war file (the warSourceExcludes configuration). I'm not sure if this is the best way but it seems to be working out quite well.

Maven: release single file, set line endings

I would like to release single file to Nexus repo (deploy script, sh) and for that purpose I am using
build-helper-maven-plugin:attach-artifact
Unlike Maven Assembly Plugin, it hasn't explicit option to set line ending of the deployed file. How can I solve the task using this or other plugin.
Important: I need file deployed as .sh and not as archive. Otherwise it's possible to switch to Maven Assembly Plugin.
Let me share final solution. I hope it would help someone one day...
pom.xml
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptors>
<descriptor>deploy-script-assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>deploy-script-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${build.directory}/${project.artifactId}-${project.version}-single/deploy-script.sh</file>
<type>sh</type>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
deploy-script-assembly.xml
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>single</id>
<formats>
<format>dir</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<files>
<file>
<source>deploy-script.sh</source>
<outputDirectory>/</outputDirectory>
<lineEnding>unix</lineEnding>
</file>
</files>
</assembly>
The maven-assembly-plugin has a format dir which is simply a folder structure on the hard drive which you can use to copy the sh script to that folder and convert linenendings and use build-helper-maven-plugin to attach that artifact afterwards.

Packing one tar created using maven assembly into another tar using maven assembly

I have created a tar(say project.tar) using maven assembly descriptor.
I need to create one more tar(say final.tar) file which would contain the previously created tar (project.tar) along with one script file.
To do this 'm trying using two descriptors specified in pom.xml. One descriptor is for project.tar and second for final.tar .
While doing so I'm facing the following error.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.4:single (default-cli) on project ede: Failed to create assembly: Error creating assembly archive bin: A tar file cannot include itself. -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.4:single (default-cli) on project ede: Failed to create assembly: Error creating assembly archive bin: A tar file cannot include itself. "
My pom.xml file is
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly/src.xml</descriptor>
<descriptor>assembly/final.xml</descriptor>
</descriptors>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</plugin>
...
I've also tried using pom.xml file as
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly/src.xml</descriptor>
</descriptors>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
<execution>
<id>bin</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly/final.xml</descriptor>
</descriptors>
<appendAssemblyId>false</appendAssemblyId>
<finalName>ede2</finalName>
</configuration>
</execution>
</executions>
</plugin>
In this way, it's not able to locate the descriptors files.
Could anyone please guide me if 'm doing anything wrong?
I know that this post is very old but I think it might need some explanations.
In my opinion, the best way for what you want to do is to use two executions of the maven-assembly-plugin. The first will generate your project tar and the second you final tar. (please read all the answer before saying that there is more simple)
Here is what I would do (and it works of course).
As I like to have the assemblies in different folders (because I think it is easier like that), I declare properties in my pom with the directories paths :
<properties>
<myproperties.assembly.project-tar.dir>${project.build.directory}/assembly-project/</myproperties.assembly.project-tar.dir>
<myproperties.assembly.final-tar.dir>${project.build.directory}/assembly-final/</myproperties.assembly.final-tar.dir>
</properties>
Then in the maven-assembly-plugin I configure the executions (never forget that the order of the executions is very important because they will be executed in the declaration order if they are binded on the same phase) :
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<id>project-tar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${myproperties.assembly.project-tar.dir}</outputDirectory>
<descriptors>
<descriptor>src/assembly/project-tar.xml</descriptor>
</descriptors>
</configuration>
</execution>
<execution>
<id>final-tar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<outputDirectory>${myproperties.assembly.final-tar.dir}</outputDirectory>
<descriptors>
<descriptor>src/assembly/final-tar.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
(you can see that the tars will be in different folders and that the project tar will not have the assembly id appended to its name so it will look like myproject-1.0.tar)
Now concerning the assemblies definitions.
For the project-tar.xml, I just include the jars in it, you can do whatever you want :
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>project</id>
<formats>
<format>tar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>
And for the final-tar.xml, I include the project tar and the scripts I have in my folder src/main/scripts :
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>final</id>
<formats>
<format>tar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${myproperties.assembly.project-tar.dir}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.tar</include>
</includes>
</fileSet>
<fileSet>
<directory>src/main/scripts</directory>
<outputDirectory></outputDirectory>
<fileMode>755</fileMode>
</fileSet>
</fileSets>
</assembly>
And there we are, you have your two tars.
There is a solution more simple which is as you did at the beginning :
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<id>project-tar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/assembly/project-tar.xml</descriptor>
<descriptor>src/assembly/final-tar.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
<configuration>
<appendAssemblyId>true</appendAssemblyId>
</configuration>
</plugin>
The descriptors order is very important of course.
The only difference with your initial solution is that I keep the property appendAssemblyId set to true because if not, the two assemblies will have the same name and when the maven-assembly-plugin will try to build the final assembly it will detect that there is a file which is already having this name and will fail saying that it cannot include itself...
With my solution in two executions, you can set the appendAssemblyId to false.
Part of the answer is to use the descriptorRef as outlined in the assembly plugin examples.
Hopefully that will give you something to get started with.

Resources