I summarize my findings:
- deb-maven-plugin: The Maven plugin deb-maven-plugin no longer exists and cannot be found on Maven central repository. It seems that it was deprecated in favor of the Unix Maven Plugin.
- unix-maven-plugin: as of December 2009, this plugin is in Alpha. Documentation is inconsistent, ran into a issues with artifact resolution, and problems with the dpkg plugin mode.
- jdeb Ant/Maven plugin: documentation does not cover how to configure the Maven plugin but instead focuses on ant.
Introducing Debian Packages
A debian package is a collection of files along with instructions on where those files should reside in the filesystem, what libraries or other programs the contents of the package are dependent on (if any), setup instructions, and basic configuration scripts. Packages usually contain precompiled software, but you can also package source code. This document describes how you can enable Debian packaging for your Maven project, making your packages easily installable using the APT and dpkg tools.
Prerequisites
In order to build your own debian packages using the debuild tool, you will need the Debian repackaging utilities which you can install with the following command:
sudo apt-get install devscripts build-essential fakeroot
Required Files
Debian packages require certain files to be packaged in the .deb archive. These files are contained within the debian folder and include the control file, changelog and optional installation and uninstallation scripts. These files, along with their contents, are covered in the next sections.
An example directory layout is given below:
distributions/deb-package/build.sh distributions/deb-package/debian/changelog distributions/deb-package/debian/compat distributions/deb-package/debian/control distributions/deb-package/debian/dirs distributions/deb-package/debian/postinst distributions/deb-package/debian/postrm distributions/deb-package/debian/preinst distributions/deb-package/debian/rules
Control File
Control files consist of key/value pairs in the format key: value. Most of these fields are optional, but a few are required. You can find the full list of fields in the Debian Policy Manual Chapter 5 - Control files and their fields.
An example control file for the mail-service is given below:
Source: acme-mail-service Priority: optional Section: devel Build-Depends: debhelper (>= 7) Maintainer: Acme CorpHomepage: http://www.acmecorp.com Package: acme-mail-service Architecture: all Depends: Description: Debian package for the Acme mail-service
Changelog
Changes in the Debian version of the package should be briefly explained in the Debian changelog file debian/changelog. This should include any changes and updates to the package. The format of the debian/changelog allows the package building tools to discover which version of the package is being built and find out other release-specific information. You can find additional information in the Debian Policy Manual Chapter 4 - Source packages.
An example changelog is given here for the mail-service:
acme-mail-service (9.11.18) unstable; urgency=low * initial revision -- Acme CorpFri, 20 Nov 2009 17:21:37 -0400
Scripts
It is possible to supply scripts as part of a package which the package management system will run for you when your package is installed, upgraded or removed. These scripts are the files preinst, postinst, prerm and postrm in the control area of the package. They must be proper executable files; if they are scripts (which is recommended), they must start with the usual #! convention. They should be readable and executable by anyone, and must not be world-writable.
The package management system looks at the exit status from these scripts. It is important that they exit with a non-zero status if there is an error, so that the package management system can stop its processing. It is also important, of course, that they exit with a zero status if everything went well. Broadly speaking the preinst is called before (a particular version of) a package is installed, and the postinst afterwards; the prerm before (a version of) a package is removed and the postrm afterwards. More information is available in the Debian Policy Manual Chapter 6 - Package maintainer scripts and installation procedure.
An example of the postinst script follows:
#!/bin/bash SERVICE_NAME=mail-service # set ownership permissions chown -R acme:acme /home/acme/packaging echo "Installing symlink for ${SERVICE_NAME} in /home/acme" ln -s /home/acme/packaging/${SERVICE_NAME} /home/acme/${SERVICE_NAME}
Similary for postrm:
#!/bin/bash SERVICE_NAME=mail-service # remove site symlink here if [ -L /home/acme/${SERVICE_NAME} ]; then echo "Removing ${SERVICE_NAME} symlink from /home/acme" rm /home/acme/mail-service fi
and preinst:
#!/bin/bash # verify that the required installation directory is present if [ ! -d /home/acme ]; then echo "Directory /home/acme was not found. Aborting!" exit 1 fi
Maven Integration
With the required Debian control files in place, we are ready to integrate the debian packaging process into the Maven build lifecycle. To this end, we introduce a helper build script which we will invoke via the Maven ant-run plugin.
Build Script
The helper build script build.sh kicks off the building of the Debian package by invoking the debuild packaging tool. An example for the mail-service is shown below:
#!/bin/sh MODULE_NAME=mail-service echo "Building Debian package for ${MODULE_NAME}" echo rm -rf ../../target/deb-pkg mkdir -p ../../target/deb-pkg # Extract the tarball to the package workspace tar xfz ../../target/${MODULE_NAME}.tar.gz --directory ../../target/deb-pkg # Add the Debian control files cp -r debian ../../target/deb-pkg # Build the package cd ../../target/deb-pkg debuild --check-dirname-level 0 -us -uc -b
Changes to pom.xml
We can easily integrate the build script above into the Maven build lifecycle with the help of the Maven ant-run plugin. In addition, we introduce a new Maven profile deb-pkg to active the building of Debian packages. This prevents Debian packages from being built by default on invoking mvn package. The following pom.xml snippet from the mail-service demonstrates this process:
<profiles> <profile> <id>deb-pkg</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <configuration> <tasks> <echo message="Creating deb package"> </echo> <exec dir="${basedir}/distributions/deb-package" executable="${basedir}/distributions/deb-package/build.sh" failonerror="true"> </exec> </tasks> </configuration> <executions> <execution> <id>deb-pkg</id> <phase>package</phase> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles>
Finally, in order to build your Debian package using Maven, you would simply invoke:
maven package -Pdeb-pkg
Advanced Topics
Setting up a Local Apt Repository
Creating a local apt repository is a great way to test your newly created Debian packages. You can do this easily with the following steps:
(i). create a directory to contain your local repo:
mkdir /tmp/apt-repo
(ii). add the following line to your /etc/apt/sources.list:
deb file:///tmp/apt-repo/ binary/
After building a new Debian package, you can add it to your repository and refresh the repository inventory by invoking:
cd /tmp/apt-repo cp /home/acme/mail-service/target/*.deb binary/ dpkg-scanpackages binary | gzip -9c > binary/Packages.gz apt-get update
Once you have setup your local apt repository, you can easily test your new debian packages by invoking apt-get install your-package for installing/updating your package, and apt-get remove your-package for uninstallation.
Adding a Service to Startup
On Linux systems, you can add your service to the appropriate run-level so that it automatically starts at bootup and stops on shutdown. As part of your Debian package, you should install a script to /etc/init.d/ with start/stop operations. An example script is given below:
#! /bin/sh # /etc/init.d/blah # # Some things that run always touch /var/lock/blah # Carry out specific functions when asked to by the system case "$1" in start) echo "Starting script blah " echo "Could do more here" ;; stop) echo "Stopping script blah" echo "Could do more here" ;; *) echo "Usage: /etc/init.d/blah {start|stop}" exit 1 ;; esac exit 0
Once your script is copied to /etc/init.d/, you can install it so that it is invoked at the appropriate run-level using the update-rc.d command:
update-rc.d myscript defaults
where myscript should be replaced with the name of your service script. This command will make links to start the service in runlevels 2345, and stop the service in runlevels 016.
Similarly, to remove a service from startup you must first remove the script from /etc/init.d/ and only then invoke:
update-rc.d myscript remove
Using the update-rc.d command, we can install and uninstall our service from the run-level using the Debian package's postinst and postrm maintainer scripts.
Further Reading
Basics of the Debian package management system
Debian Policy Manual
IBM DeveloperWorks: Create Debian Linux packages
Making scripts runt at boot time with Debian
An introduction to run-levels
Ubuntu Bootup Howto