Packaging Scripts for Debian

Table of Contents

I prefer to stick to a discipline of managing everything of significance
that I install on my systems in Debian packages. This gives me the full
power of the package system to handle dependencies, makes it easier to
ensure that I have the current version installed on all of my systems, and
avoids multiple copies of files checked into different repositories and
templates.

However, some of the software I use comes in the form of stand-alone
scripts distributed as simple downloads rather than versioned tarballs.
This requires some machinations to build a reasonable Debian package since
the normal packaging workflows assume an upstream tarball with a Makefile
and similar machinery.

This page summarizes my approach in the hope that it will save other
people some time. Most of it is obvious, but it's sometimes still nice to
have something to cut and paste.

All code examples on this page are hereby placed in the public domain if
that's possible in your jurisdiction, and in any case may be treated as if
they were in the public domain.

The first trick with scripts is to create a reasonable upstream tarball
for use as the .orig.tar.gz file. I use the following code in
debian/rules to implement a get-orig-source target, this for
an example filter-syslog script.

The number of column to print in the awk command depends on how the Id
string is represented in the script. This example assumes setting a
variable with an our delcaration. If that's not the case, you may
want $$5 instead. If you cut and paste this, be careful to change
the leading spaces in the lines after the get-orig-source: target
to tabs.

This rule downloads the script from a URL (which will need to be changed
for the script that you're using) and creates an .orig.tar.gz file
from it.

The above rule extracts the version number of the script from a CVS- or
Subversion-style Id string, which matches my convention for script
versioning. Depending on the script, you may have to do something else,
such as run the script with -v and extract the version from the
output. Unfortunately, you cannot use := or $(shell) to
extract the version number since it can't run before the new script is
downloaded.

The rest of debian/rules depends on whether you are installing a
man page you wrote yourself, or whether you're generating one from the
script. If you're installing one yourself, you can just put it into
debian/manpages and then use the fully minimal debhelper 7 rules:

#!/usr/bin/make -f
%:
dh $@

plus the get-orig-source target. If you need to generate the man
page during the build, you need something more complex. Most of the
scripts I package are in Perl with POD documentation, so I use something
like:

for the rest of debian/rules. As above, replace the awk code with
something else if needed to get the version of the script and replace
leading spaces with tabs. You can do something similar if you're using
help2man or some other system to generate the man page. Don't forget to
add the generated man page to debian/clean and to
debian/manpages.

The other packaging files are very simple and similar to a normal Debian
arch-all package. If you use the above techniques for
debian/rules, you of course need to declare a build-dependency on
debhelper (>= 7.0.50~) for override support and create a
debian/compat file containing 7.

For Perl scripts, remember that you can use ${perl:Depends} in
debian/control for the Perl dependency of the generated package,
but you still have to separately declare the dependencies on the modules
that the script uses.

If you're generating the man page during the build, remember to add a
Build-Depends-Indep line for whatever tools generate the man page.
In the case of pod2man, this is simply the perl package, but an explicit
build dependency is still good form since perl-base may not include the
pod2man components. (Yes, debhelper depends on perl so this isn't
strictly necessary, but it's not good form to rely on the dependencies of
your dependencies when you call the programs directly.)

I add a watch file containing something like this:

# Since upstream makes this script available as a simple file download
# and the download link doesn't contain the version number, there
# isn't a way to write a meaningful watch file.
#
# To check the current upstream release, go to the package home page
# and check the version number listed there.

for scripts whose download links aren't versioned. This silences Lintian
and documents the situation for anyone running DEHS or uscan on the
package.

I keep all of my Debian packaging in Git, even simple things like this.
For scripts, I use a simplified version of my normal
Git packaging structure and configuration that
maintains all Debian packaging and changes in the master branch.
The following details assume that you've already set up git-buildpackage
and friends as described there.

First, to bootstrap the repository, you want to create an upstream
branch containing just the script, a pristine-tar branch containing
the metadata for the .orig.tar.gz files that you will create, and a
master branch that will be used for releases, packaging, and
Debian-specific changes. Start with:

git init
git branch upstream

in a new empty directory. This creates an empty upstream branch
that you'll use later.

Then, what I find useful is to write the skeleton of the Debian packaging
first, particularly including the get-orig-source target in
debian/rules, and commit that to an empty repository created with
git init. Then, the following commands will bootstrap things:

replacing <script> and <version> with the name of the script and its
current version.

This process will create an upstream branch that contains just the
current version of the script as distributed by upstream and a
pristine-tar branch with the necessary information to recreate your
tarball, and then merges the upstream branch into master.
You can now finish whatever additional packaging bits you need to do and
continue as normal.

Once you've bootstrapped the repository, importing a new upstream version
is as easy as: