How to use quilt to manage patches in Debian packages

Most Debian source packages are using the “3.0 (quilt)” format. This means that Debian changes to upstream files are managed in a quilt patch series. Knowledge of quilt is thus a must if you want to get involved in some serious packaging work. Don’t worry, this tutorial will teach you how to use quilt in the context of Debian packaging.

Pre-requisites

Install the packaging-dev package to get a decent set of packages to do Debian packaging. It includes the quilt package.

$ sudo apt-get install packaging-dev

What’s quilt?

Read the description of the Debian package:

Quilt manages a series of patches by keeping track of the changes each of them makes. They are logically organized as a stack, and you can apply, un-apply, update them easily by traveling into the stack (push/pop).

Quilt is good for managing additional patches applied to a package received as a tarball or maintained in another version control system. The stacked organization is proven to be efficient for the management of very large patch sets (more than hundred patches). As matter of fact, it was designed by and for Linux kernel hackers (Andrew Morton, from the -mm branch, is the original author), and its main use by the current upstream maintainer is to manage the (hundreds of) patches against the kernel made for the SUSE distribution.

The various files involved

Stack of files PictureTo better understand the various quilt commands, you should have a basic idea of how the tool works. The “stack of patches” is maintained in a dedicated directory (“patches” by default, but in Debian packages we override this value to “debian/patches”). This directory contains the patch files and a “series” file that gives an ordered list of patches to apply. Example:

$ ls debian/patches/
01_use_stdlib_htmlparser_when_possible.diff
02_disable-sources-in-sphinxdoc.diff
03_manpage.diff
06_use_debian_geoip_database_as_default.diff
series
$ cat debian/patches/series
01_use_stdlib_htmlparser_when_possible.diff
02_disable-sources-in-sphinxdoc.diff
03_manpage.diff
06_use_debian_geoip_database_as_default.diff

When quilt is used, it also maintains some internal files in a directory of its own (it’s named “.pc”). This directory is used to know what patches are currently applied (.pc/applied-patches) and to keep backup copies of files modified by the various patches.

Configuring quilt

Before going further, you should put this in your ~/.quiltrc file:

for where in ./ ../ ../../ ../../../ ../../../../ ../../../../../; do
    if [ -e ${where}debian/rules -a -d ${where}debian/patches ]; then
        export QUILT_PATCHES=debian/patches
        break
    fi
done

This ensures that quilt will always use “debian/patches” instead of “patches” when your current directory is within a Debian source package where debian/patches exists. If you only use quilt for debian packaging, then you can be more expedient and put a simple “export QUILT_PATCHES=debian/patches” in that file.

As a matter of personal preferences, I also have those lines in my ~/.quiltrc:

QUILT_PUSH_ARGS="--color=auto"
QUILT_DIFF_ARGS="--no-timestamps --no-index -p ab --color=auto"
QUILT_REFRESH_ARGS="--no-timestamps --no-index -p ab"
QUILT_DIFF_OPTS='-p'

It enables syntax coloring for the output of several commands and customizes the generated patches to get rid of useless information. I recommend you to use those settings too.

Applying and unapplying patches, navigating in the stack of patches

When you already have a patch series, you can navigate in the stack of patches so that any subset of consecutive patches (starting from the bottom) can be applied. quilt series will list all patches known by quilt.

You can apply all patches with quilt push -a or unapply them all with quilt pop -a. You can also verify what patches are applied (quilt applied) or unapplied (quilt unapplied). quilt push applies the next unapplied patch (i.e. the patch returned by quilt next) and quilt pop unapplies the last applied patch (i.e. the patch returned by quilt top). You can give a patch name as parameter to quilt push/pop and it will apply/unapply all the patches required until the given patch is on the top.

Here are some examples of navigation in a quilt patch series

$ quilt series
02_disable-sources-in-sphinxdoc.diff
03_manpage.diff
06_use_debian_geoip_database_as_default.diff
$ quilt applied
No patches applied
$ quilt next
02_disable-sources-in-sphinxdoc.diff
$ quilt push
Applying patch 02_disable-sources-in-sphinxdoc.diff
patching file docs/conf.py

Now at patch 02_disable-sources-in-sphinxdoc.diff
$ quilt push
Applying patch 03_manpage.diff
patching file docs/man/django-admin.1

Now at patch 03_manpage.diff
$ quilt applied
02_disable-sources-in-sphinxdoc.diff
03_manpage.diff
$ quilt unapplied
06_use_debian_geoip_database_as_default.diff
$ quilt pop -a
Removing patch 03_manpage.diff
Restoring docs/man/django-admin.1

Removing patch 02_disable-sources-in-sphinxdoc.diff
Restoring docs/conf.py

No patches applied
$ quilt push 03_manpage.diff
Applying patch 02_disable-sources-in-sphinxdoc.diff
patching file docs/conf.py

Applying patch 03_manpage.diff
patching file docs/man/django-admin.1

Now at patch 03_manpage.diff
$ quilt top
03_manpage.diff

Creating a new patch

If there’s no quilt series yet, you want to create the “debian/patches” directory first.

If you already have one, you need to decide where to insert the new patch. Quilt will always add the new patch just after the patch which is currently on top. So if you want to add the patch at the end of the series, you need to run “quilt push -a” first.

Then you can use quilt new name-of-my-patch.diff to tell quilt to insert a new empty patch after the current topmost patch. In this operation quilt does almost nothing except updating the series file and recording the fact that the new patch is applied (even if still empty at this point!).

Now to add changes in this patch, you’re supposed to modify files but only after having informed quilt of your intent to modify those files. You do this with quilt add file-to-modify. At this point quilt will make a backup copy of that file so that it can generate the final patch when you’re done with your changes. It’s quite common to forget this step and to be unable to generate the patch afterward. That’s why I recommend you to use quilt edit file-to-modify which is a shorthand for doing quilt add and then opening the file in your favorite text editor.

If you want, you can review your work in progress with quilt diff.

When you’re done with the changes, you should call quilt refresh to generate the patch (or to update it if it was already existing). And since you’re a good packager, you call quilt header --dep3 -e to add DEP-3 meta-information to your patch header.

Importing an external patch

If someone else already prepared a patch, you can just import it right away with quilt import /tmp/the-patch. If you want to import it under a better name you can use the option “-P better-patch-name”. Like quilt new, it inserts the patch after the topmost patch.

Updating patches for a new upstream version

With some luck, your patches will still apply with some offsets in line numbers (quilt displays those offsets) and sometimes with some fuzz:

$ quilt push
[...]
Hunk #1 succeeded at 1362 (offset 11 lines).
Hunk #2 succeeded at 1533 with fuzz 1 (offset 4 lines).
[...]

While offsets are nothing to worry about (it means some lines were added and/or removed before the patched part), fuzz means that patch had to ignore some context lines to find the place where to apply the changes. In that case, you need to double check that patch did the right thing because it might have made changes somewhere where it shouldn’t. Also, you’ll have to update those patches because dpkg-source doesn’t accept any fuzz.

If you’re confident that all patches are correctly applied by quilt, you can refresh them to get rid of those warnings:

$ quilt pop -a
[...]
$ while quilt push; do quilt refresh; done

That was for the easy case. Now let’s deal with the case where some of the patches no longer apply. There’s one case that is usually nice to have:

$ quilt push
Applying patch 04_hyphen-manpage.diff
patching file docs/man/django-admin.1
Hunk #1 FAILED at 194.
1 out of 1 hunk FAILED -- rejects in file docs/man/django-admin.1
Patch 04_hyphen-manpage.diff can be reverse-applied

When the patch can be reverse-applied, it means that the upstream authors included the Debian patch (or that they made the same change even though you forgot to forward the patch). You can thus get rid of it:

$ quilt delete -r 04_hyphen-manpage.diff
Removed patch 04_hyphen-manpage.diff

Note that without the -r the patch is only dropped from the series file. With -r the patch file is also removed.

But there’s a less desirable case where the patch is still relevant but it doesn’t apply any longer:

$ quilt push
Applying patch 01_disable_broken_test.diff
patching file tests/regressiontests/test_utils/tests.py
Hunk #1 FAILED at 422.
1 out of 1 hunk FAILED -- rejects in file tests/regressiontests/test_utils/tests.py
Patch 01_disable_broken_test.diff does not apply (enforce with -f)

In that case, you should follow quilt’s advice to force the patch application, manually apply the parts of the patch that were rejected, and then refresh the patch.

$ quilt push -f
Applying patch 01_disable_broken_test.diff
patching file tests/regressiontests/test_utils/tests.py
Hunk #1 FAILED at 422.
1 out of 1 hunk FAILED -- saving rejects to file tests/regressiontests/test_utils/tests.py.rej
Applied patch 01_disable_broken_test.diff (forced; needs refresh)
$ vim tests/regressiontests/test_utils/tests.py    
$ quilt refresh
Refreshed patch 01_disable_broken_test.diff

Other quilt commands

You should probably read quilt’s manual page too to learn about the various other commands and options that exist.

There’s at least quilt rename new-name that you can also find useful to rename the topmost patch (you can use “-P patch-to-rename” to rename a patch which is not currently at the top).

Feedback

Please leave comments if you have suggestions of improvements, or if there are some tips that are good to know. I might incorporate them in this article.

Feel free to share this article with newbie packagers which are struggling with quilt. For your convenience, you can also refer to this article with this URL: https://raphaelhertzog.com/go/quilt

Found it useful? Be sure to not miss other packaging tips (or lessons), click here to subscribe to my free newsletter and get new articles by email.

Official Debian/Ubuntu packages for Dropbox

Dropbox is a popular service to synchronize files between multiple computers. The service is entirely proprietary but the company is Linux friendly and provides Linux binaries ready to use. They even provide Ubuntu packages that wrap the dropbox client and provide integration with Nautilus.

A bit of story

Unfortunately for Debian users, those packages do not work on Debian due to a dependency that can’t be satisfied (because Ubuntu introduced an epoch on the version of their nautilus package that Debian doesn’t have). This was even reported in a Squeeze review in Linux Weekly News.

At some point, Ivan Borzenkov introduced a dropbox package to Debian but it was not based on the above package, instead it packaged directly the proprietary binaries. This was a bad decision because the binaries bundle a set of LGPL libraries and nobody from Debian wanted to do the required work to provide the corresponding source code. So the package got dropped (see bug #610300).

More recently several persons filed ITP (Intent To Package) bugs stating their willingness to re-introduce dropbox in Debian, but after many months lingering in the bug tracking system (see #544499, #613788), they have been turned back to RFP (Request For Package) because they changed their minds.

What I did

Being a dropbox user myself (despite the recent proof that data stored on dropbox is not 100% private), I offered sponsorship to the volunteers who wanted to package dropbox. But it turns out this was not enough to motivate someone to complete the task.

In the mean time I was still using the old dropbox package that was removed (it used to be downloadable from snapshot.debian.org).

While this was good enough for me, it’s clearly not OK in the long term and way too difficult for the majority of users. So this week-end I spent some hours to create a proper package.

It’s loosely based on the package provided by Dropbox but I upgraded the packaging and changed the way it works. I patched the dropbox wrapper to provide a “dropbox update” command that downloads and updates the proprietary binaries. They are now stored in /var/lib/dropbox instead of having a copy in each user’s home directory (~/.dropbox-dist/). This update command is run by the postinst so that installing the package immediately downloads the proprietary binaries.

Get the Dropbox packages for Debian

The package nautilus-dropbox has been uploaded to Debian unstable, it’s currently in the NEW queue but will shortly reach the mirrors. Then you will be able to You can install the package with a simple apt-get install nautilus-dropbox (provided that you activated the non-free section since that’s where the package is hosted, it can’t be part of Debian since it requires the proprietary binaries to be useful).

In the mean time you can get the packages from the links below:

  • For Debian Squeeze: i386 amd64 (now in backports.debian.org)
  • For Debian unstable/wheezy: i386 amd64 (now in wheezy/sid)
  • For Debian unstable with GNOME3 from experimental: i386 amd64 (now in experimental)

Get the Dropbox packages for Ubuntu

I have setup a PPA for nautilus-dropbox. Feel free to use it in place of the upstream packages.

$ sudo add-apt-repository ppa:hertzog/nautilus-dropbox
$ sudo apt-get update
$ sudo apt-get install nautilus-dropbox

It also includes packages for oneiric, but in theory once the package is accepted into Debian, it should appear in oneiric shortly after.

Package maintenance

I have done the initial packaging work but I don’t really want to maintain it in the long term. I have more than enough to do with dpkg and my other packages. So if you are interested in maintaining this package, please get in touch with me. You should know a bit of python since there are Debian-specific patches of the upstream code. The package is maintained in a git repository.

Feedback

If you have encountered a problem with one of those packages, feel free to leave a comment.

If you’re an happy user of the above packages, click here to find out how you can thank me.

I hope you enjoy the packages!

Best practices when sponsoring Debian packages

Sponsoring a package means uploading a package for someone else (usually a new contributor starting out as package maintainer). This is an activity reserved to Debian Developer who are supposed to be knowledgeable about packaging. This article tries to document the process to ensure the sponsor is doing a reasonably good job according to Debian’s standards.

Sponsoring a package in the Debian archive is not a trivial matter. It means that you verified the packaging and that it is of the level of quality that Debian strives to have. Let’s have a look to what you can and should do when you’re sponsoring a package.

Sponsoring the initial upload

Sponsoring a brand new package into Debian requires a thorough review of the Debian packaging. Building the package and testing the software is definitely not enough! You should open every file in the debian directory and look out for potential problems. Here’s a checklist that you can use to perform the audit:

  • Verify that the upstream tarball provided is the same that has been distributed by the upstream author (when the sources are repackaged for Debian, generate the modified tarball yourself).
  • Run lintian. It will catch many common problems. Be sure to verify that any lintian overrides setup by the maintainer is fully justified.
  • Run licensecheck and verify that debian/copyright seems correct and complete. Look for license problems (like files with “All rights reserved” headers, or with a non-DFSG compliant license).
  • Build the package with pbuilder (or any similar tool) to ensure that the build-dependencies are complete.
  • Proofread debian/control: does it follow the best practices? are the dependencies complete?
  • Proofread debian/rules: does it follow the best practices? do you see some possible improvements?
  • Proofread the maintainer scripts (preinst, postinst, prerm, postrm, config): will the preinst/postrm work when the dependencies are not installed? are all the scripts idempotent (i.e. can you run them multiple times without consequences)?
  • Review any change to upstream files (either in .diff.gz, or in debian/patches/ or directly embedded in the debian tarball for binary files). Are they justified? Are they properly documented (with DEP-3 for patches)?
  • For every file, ask yourself why the file is there and whether it’s the right way to achieve the desired result. Is the maintainer following the best packaging practices described by the Developers Reference?
  • Build and install the packages, try the software. Ensure you can remove and purge the packages. Maybe test the packages with piuparts.

If the audit did not reveal any problem, you can upload the package. But remember that even if you’re not the maintainer, the sponsor is still responsible of what he uploaded to Debian. That’s why you’re encouraged to keep up with the package through the Package Tracking System.

Sponsoring an update of an existing package

You will usually assume that the package has already gone through a full review. So instead of doing it again, you will carefully analyze the difference between the current version and the new version prepared by the maintainer. If you have not done the initial review yourself, you might still want to have a more deeper look just in case the initial reviewer was sloppy.

To be able to analyze the difference you need both versions. Download the current version of the source package (with apt-get source) and rebuild it (or download the current binary packages with aptitude download). Download the source package to sponsor (usually with dget).

Read the new changelog entry, it should tell you what to expect during the review. The main tool you will use is debdiff, you can run it with two source packages (.dsc files), or two binary packages, or two .changes files (it will then compare all the binary packages listed in the .changes).

If you compare the source packages (excluding upstream files in the case of a new upstream version, for example by filtering the output of debdiff with filterdiff -i '*/debian/*'), you must understand all the changes you see and they should be properly documented in the Debian changelog.

If everything is fine, build the package and compare the binary packages to verify that the changes on the source package have no unexpected consequences (like some files dropped by mistake, missing dependencies, etc.).

You might want to check out the Package Tracking System to verify if the maintainer has not missed something important. Maybe there are translations updates sitting in the BTS that could have been integrated. Maybe the package has been NMUed and the maintainer forgot to integrate the changes from the NMU in his package. Maybe there’s a release critical bug that he has left unhandled and that’s blocking migration to testing. Whatever. If you find something that she could have done (better), it’s time to tell her so that she can improve for next time. And so that she has a better understanding of her responsibilities.

If you have found no problem, upload the new version. Otherwise ask the maintainer to provide you a fixed version.


This article will be repurposed to enhance the Debian Developers Reference, hopefully leading to a fix for the wishlist bug #453313. Click here and help me fix more of those.

You’re also welcome to suggest improvements in the comments. Are there other checks that you’re always doing? Do you have some handy tip to make it easier to review a package?

3 ways to not clutter your Debian source package with autogenerated files

It’s quite common that the upstream build system generates/updates some files but does not clean them up properly when you call make clean. In that case, when you rebuild the package a second time in the same tree, the generated Debian source package will contain those changes.

You usually don’t want those changes. They make your package harder to review because they contain unneeded modifications (either directly in the .diff.gz with the old source format, or in a new patch in debian/patches/debian-changes-<ver> with the “3.0 (quilt)” source format).

I’ll show you 3 ways to avoid this problem. They are all workarounds, the proper fix would be to improve the upstream build system to really clean up the generated files. This is usually possible for files that are “created”, but it’s much more cumbersome for files that are “updated” (you would have to keep a backup of the original file so that you can restore it).

The traditional fix

Instead of relying on the upstream build system to do the work, we modify the clean target in debian/rules to remove the files that are left-over. Since “debian/rules clean” is always called before a source package is built, those generated files are not included as changes compared to what upstream provided.

A common work-around: always build from a clean state

As you have noted, the problem only happens when you build (source and binaries) twice in a row in the same tree. Some VCS-helper tools always build the Debian package in a temporary tree which is exported from the VCS. This is the case of svn-buildpackage by default and of git-buildpackage if you use its --git-export-dir option.

I don’t like this solution because it solves the problem only for the maintainer. Anyone else who is working on top of the package without using the same VCS-helper tool would be affected by the problem.

A new way to avoid the problem

Since it’s now possible to store dpkg-source options in the source package itself, we can conveniently have everybody use the --extend-diff-ignore option. It tells dpkg-source to ignore some files when checking whether we have made changes to upstream files.

For example if you want to ignore changes made on the files “config.sub”, “config.guess” and “Makefile” you could put this in debian/source/options:

# Don't store changes on autogenerated files
extend-diff-ignore = "(^|/)(config\.sub|config\.guess|Makefile)$"

You need to know a bit about Perl regular expressions since that’s what is used by dpkg-source to match the filenames to exclude.

Note that this approach always works, even when you can’t remove the file. So it saves you having to make a backup of the unmodified file just to be able to restore it before the next build.

Found it useful? Be sure to not miss other packaging tips (or lessons), click here to subscribe to my free newsletter and get new articles by email.