View Source

Arc unpack as a debian package

First, we need to define a few properties in the pom file
{code:language=xml|title=Pom file properties}<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.deb.name>${groupId}.${artifactId}</maven.deb.name>
<maven.deb.libfolder>/usr/share/${maven.deb.name}</maven.deb.libfolder>
<maven.deb.docfolder>/usr/share/doc/${maven.deb.name}</maven.deb.docfolder>
<maven.deb.manfolder>/usr/share/man</maven.deb.manfolder>
<maven.deb.binfolder>/usr/bin</maven.deb.binfolder>
<maven.deb.assembly>debian-prepare</maven.deb.assembly>
</properties>
{code}
Basically, these just allows us to use consistent names in the plugin configs that follow.

Then we come to the <build> section. The first thing to do, is to enable filtering on the resources. This is done such
{code:language=xml}<build>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
</resource>
</resources>{code}
The effect of this is that you can use $\{maven.deb.name\}

and the like in the config files, and have this replaced during the build.&nbsp;

Firstly, we want to ensure that the jar file is as executable as we can easily make it. To do this, we must make a manifest. This is done with the jar-plugin
{code:language=xml}<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<archive>
<manifest>
<mainClass>dk.statsbiblioteket.scape.arcunpacker.Archive</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addClasspath>true</addClasspath>
<classpathPrefix>${maven.deb.libfolder}</classpathPrefix>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${pom.url}</url>
</manifestEntries>
</archive>
<excludes>
<exclude>debian/**</exclude>
<exclude>scripts/**</exclude>
</excludes>
</configuration>
</plugin>{code}
In the manifest, I declare the main class, and the classpath. Notice that I declare the classpathPrefix to be the maven.deb.libfolder, in order for the system to be able to resolve the dependencies when installed as a debian package.

Okay, the jar file is now generated correctly. Lets start on generating the package. First, we need to use maven to get all the dependencies. This is done with the assembly plugin
{code:language=xml}<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/${maven.deb.assembly}.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
{code}
This plugin uses the deb assembly. So, what will the deb.assembly do? Lets look at it.&nbsp;
{code:language=xml}<assembly>
<id>debian-prepare</id>

<formats>
<format>dir</format>
</formats>

<dependencySets>

<dependencySet>
<outputDirectory>jars</outputDirectory>
<useTransitiveDependencies>true</useTransitiveDependencies>
<useTransitiveFiltering>true</useTransitiveFiltering>
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>

</dependencySets>

</assembly>
{code}
Basically, it puts all the jar dependencies of the project in one dir, ready for inclusion in the debian package.&nbsp;

Time to make the first version of the deb. We need another plugin in the pom file to do that.
{code:language=xml}<plugin>
<artifactId>jdeb</artifactId>
<groupId>org.vafer</groupId>
<version>0.9</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jdeb</goal>
</goals>
<configuration>
<deb>${project.build.directory}/${artifactId}${version}-java.deb</deb>
<controlDir>${project.build.directory}/classes/debian/control/</controlDir>
                            <dataSet> <dataSet>
<data>
<src>${project.build.directory}/${project.build.finalName}-${maven.deb.assembly}/${project.build.finalName}/jars</src>
<type>directory</type>
<mapper>
<type>perm</type>
<prefix>${maven.deb.libfolder}</prefix>
</mapper>
</data>
<data>
<src>${project.build.directory}/${project.build.finalName}.jar</src>
<type>file</type>
<mapper>
<type>perm</type>
<prefix>${maven.deb.libfolder}</prefix>
</mapper>
</data>

</dataSet>
</configuration>
</execution>
</executions>
</plugin>
{code}
Note that it is important that this plugin is placed below the assembly plugin, as they both execute in the package phase, and jdeb depends on the debian assembly having been run.

So, what will this plugin do?

Well, it will make a debian package, with the filename $\{project.build.directory\}/$\{artifactId\}$\{version\}-java.deb.

The ever-important control file should be found in&nbsp;$\{project.build.directory\}/classes/debian/control/ More about that file later.

The lib folder&nbsp;$\{maven.deb.libfolder\} should contain the jars, from the debian-prepare assembly detailed above. Oh, and the project jar should also go there, as it was not included in the assembly.

So, now we just need to detail the control file, and we have the first barebone deb file.&nbsp;

Make a file "control" in resources/debian/control, with this content
{code:language=none}Package: [[groupId]].[[artifactId]]
Version: [[version]]
Section: java
Priority: optional
Architecture: all
Depends: default-jre (>= 1.5)
Maintainer: Asger Askov Blekinge <[email protected]>
Description: unpacker app for arc and warc files, based on the heritrix crawler
This is the extended description
{code}skfjklsdj

Now we should generate the deb, to check that what we have done so far works. Run mvn package.

Then we should check the deb. CD to the target directory, and use the lintian tool (lintian \*.deb). Install it if you do not have it (sudo apt-get install lintian)

The tool should produce this error&nbsp;
{code}E: dk.statsbiblioteket.scape.arc-unpacker: no-copyright-file{code}
So we should include a copyright file. Make a file "copyright" with the following content in "resources/debian/copyright"
{code}Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Files: *
Copyright:
Copyright (C) 2012 by State and University Library, Denmark
License: Apache-2.0
/usr/share/common-licenses/Apache-2.0
{code}Now jdeb needs to be told to include this file. Add the following section to the plugin's list of datasets
{code}<data>
<src>${project.build.directory}/classes/debian/copyright</src>
<type>directory</type>
<mapper>
<type>perm</type>
<prefix>${maven.deb.docfolder}</prefix>
</mapper>
</data>
{code}mvn clean package to generate the package once more, and lintian it again. The error should now be
{code}E: dk.statsbiblioteket.scape.arc-unpacker: changelog-file-missing-in-native-package{code}
Okay, so we need to make a changelog file for debian.&nbsp;

Here is some sample content for at changelog file, that we can use&nbsp;
{code}${maven.deb.name} (0.8.10) unstable; urgency=low

* Minor bugfix releases:

o manual page confused --dbname and --dbsystem (Closes: #573235)

o applied patch by Warren Thompson to use the registered default
currency rather than a hard-code 'USD'

* debian/control: Standards-Version: increased to 3.8.4
* debian/source/format: Added with "3.0 (native)"
* debian/rules: Updated Perl invocation

-- Dirk Eddelbuettel <[email protected]> Sun, 13 Jun 2010 17:24:30 -0500

${maven.deb.name} (0.8.9) unstable; urgency=low

* Minor bugfix releases:

o DateCalc() now requires an error code variable, so supply one

o finally release the OandA fx code (Closes: #532743)

* debian/control: Standards-Version: increased to 3.8.3

* debian/copyright: Updated to newer format

-- Dirk Eddelbuettel <[email protected]> Tue, 22 Dec 2009 20:13:59 -0600
{code}Put this content in "resources/debian/changelog/changelog

Regenerate the package and validate it once more. The error should now be
{code}E: dk.statsbiblioteket.scape.arc-unpacker: changelog-file-not-compressed changelog
{code}
So, the changelog should be compressed. I have found that the antrun plugin seems to be the simplest way of doing this
{code:language=xml}<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>prepare-package</phase>
<configuration>
<target>
<exec executable="gzip">
<arg value="-9"/>
<arg value="-r"/>
<arg value="${project.build.directory}/classes/debian/changelog/"/>
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
{code}So, after this change, the deb package should validate. But we have forgotten something. The most important thing, actually. The executable file.

Since this is a java program, we use a shell script to start the program. Create the file "resources/scripts/arc-unpack" with the following content
{code:language=bash}#!/bin/sh
java -jar ${maven.deb.libfolder}/${project.build.finalName}.jar $*
{code}Remember, this file is in resources, so maven will replace the keys when compiling. Now, we need to tell jdeb to include this file. This is done by adding the following definition to the set of datasets
{code:language=xml}<data>
<src>${project.build.directory}/classes/scripts</src>
<type>directory</type>
<mapper>
<type>perm</type>
<prefix>${maven.deb.binfolder}</prefix>
<filemode>755</filemode>
</mapper>
</data>
{code}Regenerate and validate the deb file. You should now receive the following warning:
{code}W: dk.statsbiblioteket.scape.arc-unpacker: binary-without-manpage usr/bin/arc-unpack{code}So, we need to add man pages to the project.&nbsp;

Create the file "arc-unpack.8" in resources/man/man8, and give it this content:
{code:language=none|title=sample stolen manpage}.TH arc-unpack 8 "September 10, 2003" "version 0.3" "USER COMMANDS"
.SH NAME
cdspeed \- decrease the speed of you cdrom to get faster access time
.SH SYNOPSIS
.B cdspeed
[\-h] [\-d device] \-s speed
.SH DESCRIPTION
Modern cdrom drives are too fast. It can take several seconds
on a 60x speed cdrom drive to spin it up and read data from
the drive. The result is that these drives are just a lot slower
than a 8x or 24x drive. This is especially true if you are only
occasionally (e.g every 5 seconds) reading a small file. This
utility limits the speed and makes the drive more responsive
when accessing small files.
.PP
cdspeed makes the drive also less noisy and is very useful if
you want to listen to music on your computer.
.SH OPTIONS
.TP
\-h
display a short help text
.TP
\-d
use the given device instead of /dev/cdrom
.TP
\-s
set the speed. The argument is a integer. Zero means restore maximum
speed.
.SH EXAMPLES
.TP
Set the maximum speed to 8 speed cdrom:
.B cdspeed
\-s 8
.PP
.TP
Restore maximum speed:
.B cdspeed
\-s 0
.PP
.SH EXIT STATUS
cdspeed returns a zero exist status if it succeeds to change to set the
maximum speed of the cdrom drive. Non zero is returned in case of failure.
.SH AUTHOR
Guido Socher (guido (at) linuxfocus.org)
.SH SEE ALSO
eject(1){code}
It is important that the file starts with ".TH arc-unpack 8" but the rest seems optional

Now we need to tell jdeb to include this file also. Add this section to the plugins list of datasets
{code:language=none}<data>
<src>${project.build.directory}/classes/debian/man</src>
<type>directory</type>
<mapper>
<type>perm</type>
<prefix>${maven.deb.manfolder}</prefix>
</mapper>
</data>
{code}Clean, regenerate and validate the package.

The error received now should be
{code}E: dk.statsbiblioteket.scape.arc-unpacker: manpage-not-compressed usr/share/man/man8/arc-unpack.8{code}

So, we need to compress this file also. Change the antrun plugin to include the man folder also, like this.

{code}<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>prepare-package</phase>
<configuration>
<target>
<exec executable="gzip">
<arg value="-9"/>
<arg value="-r"/>
<arg value="${project.build.directory}/classes/debian/man/"/>
</exec>
<exec executable="gzip">
<arg value="-9"/>
<arg value="-r"/>
<arg value="${project.build.directory}/classes/debian/changelog/"/>
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
{code}The package should now be complete and validate. Lets try to install it.