Packaging Maven project
This step by step guide will show you how to package Maven project. Let’s start with probably the simplest spec file possible.
Unresolved directive in packaging_maven_project.adoc - include::{EXAMPLE}maven_project/simplemaven.spec[]
The spec file above is a real world example how it may look like for simple Maven project. Both %build
and %install
sections consist only of one line.
Another interesting line:
10: BuildRequires: maven-local
All Maven projects need to have BuildRequires
on maven-local
. They also need to have Requires
and BuildRequires
on jpackages-utils
, but build system adds these automatically. The package maintainer does not need to list them explicitly.
31: %dir %{_javadir}/%{name}
By default, resulting JAR files will be installed in %{_javadir}/%{name}
, therefore the package needs to own this directory.
The build could fail from many reasons, but one probably most common is build failure due to missing dependencies.
We can try to remove these missing dependencies from pom.xml and make Maven stop complaining about them. However, these removed dependencies may be crucial for building of the project and therefore it may be needed to package them later. Let’s remove the dependencies from pom.xml
.
...
%prep
%setup -q
# Add following lines to %prep section of a spec file
%pom_remove_dep :commons-io
%pom_remove_dep :junit
The package maintainer can use a wide variety of “pom_” macros for modifying pom.xml
files. See the [_macros_for_pom_modification] section for more information.
Now try to build the project again. The build will fail with a compilation failure.
Oops, another problem. This time Maven thought it had all the necessary dependencies, but Java compiler found otherwise.
Now it is possible to either patch the source code not to depend on missing libraries or to package them. The second approach is usually correct. It is not necessary to package every dependency right away. The maintainer could package compile time dependencies first and keep the rest for later (test dependencies, etc.). But Maven needs to know that it should not try to run tests now. This can be achieved by passing -f
option to %mvn_build
macro. Maven will stop complaining about missing test scoped dependencies from now on.
Another reason to disable the test phase is to speed up the local build process. This can also be achieved by specifying an additional switch Another switch |
It is always recommended to run all available test suites during build. It greatly improves quality of the package. |
We already have package which provides commons-io:commons-io
artifact, let’s add it to the BuildRequires
. Also disable tests for now.
BuildRequires: maven-local
BuildRequires: apache-commons-io
...
%prep
%setup -q
# Comment out following lines in %prep section
#%%pom_remove_dep :commons-io
#%%pom_remove_dep :junit
%build
# Skip tests for now, missing dependency junit:junit:4.11
%mvn_build -f
One can easily search for package which provides the desired artifact. Try |
Now try to build the project one more time. The build should succeed now. Congrats, you managed to create an RPM from Maven project!
There is plenty of other things maintainer may want to do. For example, they may want to provide symbolic links to the JAR file in %{_javadir}
.
This can be easily achieved with %mvn_file
macro:
%prep
%setup -q
%mvn_file : %{name}/%{name} %{name}
See [_alternative_jar_file_names] section for more information.
Another quite common thing to do is adding aliases to Maven artifact. Try to run rpm -qp --provides
on your locally built RPM package:
$ rpm -qp --provides simplemaven-1.0-1.fc21.noarch.rpm
mvn(com.example:simplemaven) = 1.0
simplemaven = 1.0-1.fc21
The output above tells us that the RPM package provides Maven artifact com.example:simplemaven:1.0
. Upstream may change the groupId:artifactId
with any new release. And it happens. For example org.apache.commons:commons-io
changed to commons-io:commons-io
some time ago. It is not a big deal for package itself, but it is a huge problem for other packages that depends on that particular package. Some packages may still have dependencies on old groupId:artifactId
, which is suddenly unavailable. Luckily, there is an easy way how to solve the problems like these. Package maintainer can add aliases to actually provided Maven artifact.
%mvn_alias org.example:simplemaven simplemaven:simplemaven
See [_additional_mappings] for more information on %mvn_alias
.
Rebuild the pacakge and check rpm -qp --provides
output again:
$ rpm -qp --provides simplemaven-1.0-2.fc21.noarch.rpm
mvn(com.example:simplemaven) = 1.0
mvn(simplemaven:simplemaven) = 1.0
simplemaven = 1.0-2.fc21
Now it does not matter if some other package depends on either of these listed artifact. Both dependencies will always be satisfied with your package.
One could try to fix dependencies in all the dependent packages instead of adding an alias to single package. It is almost always wrong thing to do. |
Want to help? Learn how to contribute to Fedora Docs ›