Maven Recipe: Delivering applications as RPMs

In the Java world, the standard unit of delivery is the jar/war/(x)ar file. For applications which don’t fit the ‘single file’ delivery model, there is no standard alternative.  To provide a solution, I will show you how to package your application with Maven as an RPM.

As we are talking about Maven, the solution starts with finding the right plugin – in our situation the rpm-maven-plugin. We include the plugin as follows:

 <groupId>org.codehaus.mojo</groupId>
 <artifactId>rpm-maven-plugin</artifactId>
 <version>2.0.1</version>

The goal we need to execute is rpm – and it attaches itself to the package phase by default – so far so good.

The configuration that is usually done in a RPM spec file is done inside the plugin’s configuration block. First, we list some required descriptive elements:

<configuration>
  <copyright>2010, NoBody</copyright>
  <group>Development</group>
  <description>Maven Recipe: RPM Package.</description>

Now we get to the core of the RPM – listing the files to deploy. As we want to deploy our application’s classes and the ones from our dependencies, we create a mapping:

<mappings>
  <mapping>
    <directory>${app.home}/lib/</directory>
    <dependency/>
  <artifact/>
</mapping>

This is a very compact way of declaring that we want all dependencies – the dependency tag – and our primary build artifact – the artifact tag – to be deployed to the lib directory of our application.

The next step is to take the app.properties file which is checked into source control and deploy it as a sample file in the conf directory, so that we have a reference at hand when configuring the application:

<mapping>
  <directory>${app.home}/conf</directory>
  <configuration>true</configuration>
  <sources>
    <source>
      <location>${project.build.outputDirectory}/app.properties</location>
      <destination>app.sample.properties</destination>
    </source>
  </sources>
</mapping>

Using location and destination we have absolute control over what is included and where it is placed. Also note the usage of the configuration tag, which translates in to the %config RPM macro, which means that changes to the file are preserved when updating or removing RPM  ( details on the RPM %config macro ).

Last, we need to generate an empty logs directory for our application. This is done simply by declaring a mapping with no sources.

<mapping>
  <directory>${app.home}/logs</directory>
</mapping>

Right now we can build a RPM out of our application. I’ve added hibernate 3.3.2.GA as a dependency, since it brings in a few transitive dependencies.

robert@neghvar:~/workspace/rpm-package> mvn clean package
[INFO] Scanning for projects...                          
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Recipe: RPM Package                                      
[INFO]    task-segment: [clean, package]                                       
[INFO] ------------------------------------------------------------------------
.........
[INFO] Wrote: /home/robert/workspace/rpm-package/target/rpm/rpm-package/RPMS/rpm-package-0.0.1-SNAPSHOT20100520205409.noarch.rpm   
...........
[INFO] ------------------------------------------------------------------------                                                     
[INFO] BUILD SUCCESSFUL                                                                                                             
[INFO] ------------------------------------------------------------------------                                                     
[INFO] Total time: 5 seconds                                                                                                        
[INFO] Finished at: Thu May 20 23:54:11 EEST 2010                                                                                   
[INFO] Final Memory: 15M/174M                                                                                                       
[INFO] ------------------------------------------------------------------------

Let’s verify that the RPM file indeed contains all that we asked it to:

robert@neghvar:~/workspace/rpm-package> rpm -qlp /home/robert/workspace/rpm-package/target/rpm/rpm-package/RPMS/rpm-package-0.0.1-SNAPSHOT20100520205409.noarch.rpm
/opt/app/conf                                                                                                                                                      
/opt/app/conf/app.sample.properties                                                                                                                                
/opt/app/lib                                                                                                                                                       
/opt/app/lib/antlr-2.7.6.jar                                                                                                                                       
/opt/app/lib/commons-collections-3.1.jar                                                                                                                           
/opt/app/lib/dom4j-1.6.1.jar                                                                                                                                       
/opt/app/lib/hibernate-core-3.3.2.GA.jar                                                                                                                           
/opt/app/lib/jta-1.1.jar                                                                                                                                           
/opt/app/lib/rpm-package-0.0.1-SNAPSHOT.jar                                                                                                                        
/opt/app/lib/slf4j-api-1.5.8.jar                                                                                                                                   
/opt/app/lib/xml-apis-1.0.b2.jar                                                                                                                                   
/opt/app/logs

We have reached our goal of building an RPM with our applications dependencies, classes and configuration files. By using the rpm-maven-plugin we have managed to keep using Maven as our build tool interface, and also reused the information available in the POM file for declaring dependencies.

The complete source code for this article is available at http://github.com/rombert/Maven-Recipe–RPM-Package . If you have any suggestions or corrections, please comment. Or better yet, fork me.

About these ads

16 Comments »

  1. [...] been lead to a page describing how RPMs can be built using a Maven [...]

  2. Nacho said

    Thanks a lot dude :)

    • Robert said

      You’re welcome :-)

  3. Binod Suman said

    Hi Robert,

    Thanks for sharing this good tutorial. I tried to search lot but didnt get any good example stright forward.

    Thanks Again. :)

    Binod Suman
    INDIA

    • Robert said

      You’re welcome, glad I could help.

  4. Thanks a lot for sharing this!

    • Robert said

      You’re welcome.

  5. Jamila said

    Hello,

    I read you article and it’s very interresting. I want to know if you have already use “RPM Package Dependency Management” and provides?
    Because I want to create a container with an rpm and virtual dependecies to other rpm …

    Thanks in advance

    Jamila

  6. shakeer said

    what is ${project.build.outputDirectory}/app.properties?
    ${app.home}?

    • Robert said

      ${app.home} is an arbitrary location I define to be the root of the installation.
      ${project.build.outputDirectory} is the standard Maven directory where the files are placed during the build.

      I suggest you take the GitHub project for a spin, there’s a link at the end of the article.

  7. Is there any dependency on Linux? I mean I am following your tutorial and for some reason it is failing. Obviously maven is os independent, rpm plugin I haven’t found any restriction on plugin’s page, and all linux paths I converted to windows. Not sure what might go wrong.
    One more qutestion: When you say “${app.home} is an arbitrary location I define to be the root of the installation” – does that mean that if the rpm package is installed that that is the location where the installation lives?
    Thanks for clarification and sorry, I am not that familiar with rpm

    • Robert said

      The plugin depends on a rpmbuild binary being available. I’m not sure you can get than on Windows.

      As for the “${app.home}” location, that’s the location where the package will be installed in the filesystem when the RPM is installed.

  8. Himanshu said

    Getting …
    [ERROR] Failed to execute goal org.codehaus.mojo:rpm-maven-plugin:2.0.1:rpm (generate-rpm) on project : RPM query for default vendor returned: ’1′ executing ‘cmd.exe
    /X /C “rpm -E %{_host_vendor}”‘ -> [Help 1]
    Tried almost everything, but still the same error…

    • Robert said

      It seems that you need the rpm tooling installed. On Linux it’s pretty easy, but I have no idea if it can be done on Windows

RSS feed for comments on this post · TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: