Packaging into a tar file in maven without creating a jar file - maven

I'm trying to package a text based file into .tar using maven. To achieve this I used an assembly plugin and it worked, but along with the file tar a jar is also being generated. How can I avoid that?
<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>configuration</directory>
<fileMode>0444</fileMode>
</fileSet>
</fileSets>
</assembly>

You can change the packaging of your project.
I guess current packaging is jar, and thus the creation of a jar.
You may use pom and configure the assembly plugin to attach its result (the tar) to your build.
You could also configure the jar plugin, to skip the creation of empty jar (if it is your case).
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<skipIfEmpty>true</skipIfEmpty>
</configuration>
</plugin>

Related

Can Maven package a WAR as .tar.gz?

I'm building a WAR application in Maven and I need to deploy it to Docker. The issue is that docker doesn't support the zip format (but can use a .tar.gz or .tar.xz).
So, how can I package my mywebapp-1.0.0.war as mywebapp-1.0.0.tar.gz?
We have this requirement so it would become easier to perform the hardening steps for the docker image.
I tried using the Assembly plugin and it produces a target/mywebapp-1.0.0.tar.gz. However, it ends up placing the whole WAR file inside a .tar.gz file, and NOT its contents. Here's my assembly.xml file:
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0
http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>distribution</id>
<formats>
<format>tar.gz</format>
</formats>
<fileSets>
<fileSet>
<outputDirectory>/</outputDirectory>
<includes>
<include>target/mywebapp-1.0.0.war</include>
</includes>
</fileSet>
</fileSets>
</assembly>
Although I find the requirement strange (the application server should unpack your war, not you), I guess it is possible by tarring the directory in target that is used to build the war.
Before the package step, all the files for the war are gathered in a directory just below target (I forgot the name, but it should be easy to reverse engineer) - just pack that directory by using the assembly plugin.
Edit by the OP:
I wanted to accept this answer but I also wanted it to be useful to someone else so I added the working solution (assembly.xml file). Here it is:
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0
http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>docker</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target/${project.build.finalName}</directory>
<outputDirectory>.</outputDirectory>
</fileSet>
</fileSets>
</assembly>
This solution generates the file target/mywebapp-1.0.0-docker.tar.gz in addition to the typical war file.
Notice it added the docker classifier.

Maven, exclude all classes but one under a package

This may sound silly, but I really want to know if I can do that (by adding some 'magic' configuration in pom.xml).
Let's say, I have a project which has a bunch of packages, one of them, say 'com.foo.bar', has quite a few .java files, including one named 'Dummy.java'.
Now, when generating the jar file, I want to exclude all classes under com.foo.bar, except the 'Dummy'.
I tried regular expression in a section, but no luck.
Is there an easy way to go? Many thanks.
With a "sledge hammer" (assuming Dummy.class not .java):
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<includes>
<include>com/foo/bar/Dummy.class</include>
</includes>
<!-- alternatively(!) excludes/exclude* -->
</configuration>
</plugin>
... or with a "Swiss army knife": maven-assembly-plugin ... ^^!"%/"))
...
To use the Assembly Plugin in Maven, you simply need to:
choose or write the assembly descriptor to use,
configure the Assembly Plugin in your project's pom.xml,
and
run "mvn assembly:single" on your project.
...
with an assembly descriptor like:
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0
http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>dummy-only</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<outputDirectory>/</outputDirectory>
<directory>${project.build.outputDirectory}</directory>
<includes>
<include>com/foo/bar/Dummy.class</exclude>
</includes>
</fileSet>
</fileSets>
</assembly>
see also: I wish to exclude some class files from my jar. I am using maven-assembly-plugin. It still adds the files. I dont get any error

Using Jenkins to publish tar.gz to Nexus

This is problem I am trying to solve:
checkout code from Github to a local directory D
run configure command inside directory D
create a tar.gz for directory
upload taz.gz file to Nexus
I am stuck at step 3:
- I can specify the version in Maven pom.xml file, but is there a way to automatically create a build version every time Jenkins is run?
- If I specify tar.gz in pom.xml file, I would get: Unknown packaging: gz # line 6, column 13
If I specify jar inside packaging, there is no error, and files are upload to Nexus successfully.
Any advice would help, thanks!
==
follow suggestion, I am using Assembly Plugin, but still having trouble create tar.gz for Directory RE
Here is my pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.o$
<modelVersion>4.0.0</modelVersion>
<groupId>Auc</groupId>
<artifactId>RE</artifactId>
<version>1.0.0.112</version>
<!-- <packaging>tgz</packaging> -->
<name>RE Repository</name>
<url>http://nexus1.ccorp.com/nexus</url>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<configuration>
<descriptors>
<descriptor>format.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Here is my format.xml file, RE directory is where I checked out the code and want to create tar.gz for it
<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>bundle</id>
<formats>
<format>tar.gz</format>
</formats>
<moduleSets>
<moduleSet>
<sources>
<fileSets>
<fileSet>
<directory>/var/lib/jenkins/jobs/nightly_build/workspace/RE</directory>
</fileSet>
</fileSets>
</sources>
</moduleSet>
</moduleSets>
<includeBaseDirectory>false</includeBaseDirectory>
Here is what we end up with:
mvn deploy:deploy-file -DgroupId=Home -DartifactId=RE -Dversion=0.0.0.1-SNAPSHOT -Dpackaging=tar.gz -DrepositoryId=Auc -Durl=http://nexus1.ccorp.com/nexus/content/repositories/snapshots -Dfile=RE-0.0.0.1-SNAPSHOT.tar.gz
Make sure -DrepositoryId=Auc, Auc is the deployment id you set in your setting.xml
<server>
<id>Auc</id>
<username>deployment</username>
<password>deployment123</password>
</server>
You have to use the Maven Assembly Plugin to create the tar.gz and then you can deploy it as usual with
mvn clean deploy
and the right settings.xml available on Jenkins with credentails as needed for the deployment.

Maven - using assembly plugin in multi-module project to create distribution file

I'm using Maven to build a multi module project;
which comprises of 9 war modules
Each module has its own POM containing instructions on how to package;
<packaging>war</packaging>
A parent POM is then responsible for initiating the Maven lifecycle on each module and pushing to an artifact manager (Nexus)
<modules>
<module>module1</module>
<module>module2....
I would like to use the assembly plugin to package each of the WAR files which were built earlier by each module into a single ZIP file. I'm attempting to do this by defining an assembly descriptor in the parent POM which defines a separate dependencySet for each of the modules (using groupID, artifactID and version to find the WAR in my local repo).
I've tried to achieve this using the following assembly file;
<assembly>
<id>war</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>zip</format>
</formats>
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<includes>
<include>com:test-web:war:${pom.version}</include>
</includes>
<outputFileNameMapping>test-web.war</outputFileNameMapping>
</dependencySet>
</dependencySets>
</assembly>
And this is the plugin configuration in my parent POM;
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<id>distribution-package</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<runOnlyAtExecutionRoot>true</runOnlyAtExecutionRoot>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
</configuration>
</execution>
</executions>
</plugin>
Is this approach on the right track?
Additionally does it make sense to pull the WAR files from my local repo? Should i be using the output in each of the sub modules target folders instead?
1) In your parent pom I would go like
<modules>
<module>module1</module>
<module>distibution</module>
<module>module2....
(create an extra module for the distribution) In order to separate the parent pom from the distribution.
2) You should not be using the output in each of the sub modules target folders. Add all wars as dependencies of the distribution. In that way maven can know that it must build the distribution LAST.
3) Tip: replace ${pom.version} with ${project.version} (I think the former is deprecated if it works at all)

Including an unpacked War in the Assembly

I have a project which builds a war (no problem). And, that war needs to be packaged with a few shell scripts. Because that war contains properties files that vary from site-to-site, we can't simply install the war as is, but munge the properties files in it. That's what the shell scripts do.
I'd like to package my war in my assembly as a unpacked war. I see <unpacked> in the Assembly Descriptor, but I haven't been able to get that to work.
Here's my first bin.xml where I just packed the war as is. This works fine:
<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>bin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/scripts</directory>
<includes>
<include>deploy.sh</include>
<include>lock_build.sh</include>
<include>description.sh</include>
<include>url-encode.pl</include>
</includes>
<outputDirectory>/</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.build.directory}/${project.artifactId}-${project.version}</directory>
<outputDirectory>${project.artifactId}</outputDirectory>
</fileSet>
</fileSets>
</assembly>
Here's my first attempt at unpacked:
<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>bin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/scripts</directory>
<includes>
<include>deploy.sh</include>
<include>lock_build.sh</include>
<include>description.sh</include>
<include>url-encode.pl</include>
</includes>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
<moduleSets>
<moduleSet>
<includes>
<include>{$project.groupId}:${project.artifactId}:war</include>
</includes>
<binaries>
<includes>
<include>${project.build.directory}-${project.artifactId}-${project.version}.${project.packaging}</include>
</includes>
<outputDirectory>${project.artifactId}</outputDirectory>
<unpack>true</unpack>
</binaries>
</moduleSet>
</moduleSets>
</assembly>
Here's my last try at getting the unpacked war:
<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>bin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/scripts</directory>
<includes>
<include>deploy.sh</include>
<include>lock_build.sh</include>
<include>description.sh</include>
<include>url-encode.pl</include>
</includes>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
<moduleSets>
<moduleSet>
<binaries>
<attachmentClassifier>war</attachmentClassifier>
<outputDirectory>${project.artifactId}</outputDirectory>
<unpack>true</unpack>
<includeDependencies>true</includeDependencies>
<dependencySets>
<dependencySet/>
</dependencySets>
</binaries>
</moduleSet>
</moduleSets>
</assembly>
In each of these last two attempts, I am only packaging the scripts and the war isn't coming over.
I know I could use the ${project.build.directory}/${project.artifactId}-${project.version} directory which contains almost all of the files in the war, but it doesn't contain my MANIFEST.MF entries which includes information linking the war back to a particular Jenkins build and Subversion revision.
What do I need to do to include an unpacked war into my assembly?
Another Attempt
<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>bin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/scripts</directory>
<includes>
<include>deploy.sh</include>
<include>lock_build.sh</include>
<include>description.sh</include>
<include>url-encode.pl</include>
</includes>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>${project.artifactId}</outputDirectory>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
When I ran this, I got:
[INFO] ------------------------------------------------------------------------
[INFO] Building My Project 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-assembly-plugin:2.5.2:single (default-cli) # myproj ---
[INFO] Reading assembly descriptor: src/assembly/bin.xml
[WARNING] Cannot include project artifact: \
com.vegicorp:myproj:war:1.0.0; \
it doesn't have an associated file or directory.
[INFO] Building zip: ~/workdir/trunk/myproj/target/archive/myproj.zip
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Inside the zip are all the jars in the war nice and unpacked, but not my unpacked war.
I know I should be able to add the unpacked war into my assembly. I see that unpack option, and I know it works for other dependencies. However, it looks like I can only access it via a <dependencySet> or a <moduleSet>. I should be able to specify my project as its own module. There must be something I am doing wrong.
Spleen Vent
This is the big thing I hate about Maven: Maven does a great job hiding things from you which is nice because it prevents you from doing stuff you shouldn't. I hate it when developers build Ant build.xml files because most developers don't understand how to do a build, and the build.xml becomes an unreadable mess. With Maven, this isn't an issue. Just configure your project, and Maven will take care of this for you.
But sometimes Maven is like a black box with a bunch of levers and buttons. You sit there pushing and pulling levers and buttons trying to figure out how to get it to do something you want to do. I spend way too much of my time trying to help developers to configure their Maven projects. They want to do something a little different like use hibernate or build source from WSDL files, and have no idea how to get Maven to do what they want.
One developer describes it as a self driving car which can't quite go where you want. You may even see the destination out the window, but you can't figure out how to manipulate the car's destination to get you there.
What I want to do should be easy. I just want to create an assembly, and instead of using the packed war file, I want it unpacked.
In Ant, this can be accomplished in a single task. In Maven, it's a mysterious process. I think I'm close, I am probably missing one little configuration parameter that will make it all work, but I've already spent hours working on this.
What I ended up doing
I used the maven-dependency-plugin to unpack my war. I wasn't sure whether this would work because I didn't want the dependency plugin downloading the war, but it seems to understand that when I specify my war, I am talking about the current build, and nothing is downloaded. (I don't even have the war in our Maven repo).
I also had to upgrade Maven from 2.x to 3.x because I need to make sure that the maven-dependency-plugin ran before the maven-assembly-plugin. Since both run in the packaging phase of the build, Maven 2.x can't guarantee the order the plugins run in.
Once I used that plugin, all I had to do was specify the directory where I unpacked the war in my assembly plugin, and it was included in my zip.
I still want to know how to use the <unpack> entity in the assembly plugin itself instead of having to use another plugin to unpack my war. If anyone can tell me how to do the unpack in the assembly file itself, I'll mark that as the correct answer.
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/unwar/${project.artifactId}</outputDirectory>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<type>war</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<finalName>${project.artifactId}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}/archive</outputDirectory>
<descriptors>
<descriptor>src/assembly/bin.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
bin.xml (My Assembly)
<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>bin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/assembly/scripts</directory>
<fileMode>0755</fileMode>
<lineEnding>lf</lineEnding>
<includes>
<include>deploy.sh</include>
<include>lock_build.sh</include>
<include>description.sh</include>
<include>url-encode.pl</include>
</includes>
<outputDirectory>/</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.build.directory}/unwar</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
The ACTUAL Answer
Thanks to khmarbaise's link (see the comment below), I copied that project's assembly plugin and it almost worked. Like my attempt, it unpacked all the runtime jars, and not just the one I wanted. However, it also unpacked my war too.
There were only two differences between that link's answer and my attempt:
They included <useProjectArtifact>true</useProjectArtifact> and I didn't. However, this defaults to true. Removing it still allowed it to work.
They included a / in front of the directory name in the <outputDirectory>. Removing this made no difference.
This meant that it now matched what I had previously tried. So, why was it working this time.
Turns out, I was testing the assembly changes by simply running mvn assembly:single. After all, why do the whole build and repackage when I am simply trying to get the assembly to work. When you run just mvn assembly:single -- even though everything is already packaged, you get this error:
[WARNING] Cannot include project artifact: \
com.vegicorp:myproj:war:1.0.0; \
it doesn't have an associated file or directory.
And your war isn't unpacked. However, if you put the assembly into the package phase, and then run mvn package, everything works out just nifty.
I then spent time trying to just get my war and not all the associated runtime stuff with it. I used <includes/> to do this, but because I have a war and not a jar, I had to include a classifier in my <include>.
At last, I have everything working. I have this in my assembly:
<dependencySets>
<dependencySet>
<outputDirectory>${project.artifactId}</outputDirectory>
<unpack>true</unpack>
<scope>runtime</scope>
<includes>
<include>${project.groupId}:${project.artifactId}:*:${project.version}</include>
</includes>
</dependencySet>
</dependencySets>
And as long as I run mvn package, it works.
This is way better than what I had with the maven-dependency-plugin. Now, all of the information having to do with the assembly is in the assembly XML file.

Resources