As a follow-up to the previous Debian packaging article, here is a second go at documenting for future me a couple more obscure concepts around building custom packages.
Virtual Packages
So today I learned how to create virtual
packages.
For those unaware, Debian has a way for packages to state that they satisfy
more than just a single package name. In the canonical example, there are
dozens of packages that can fill the generic dependency of www-browser
, such
as firefox
, chromium-browser
, or konquoror
. When a package doesn’t
particularly care which specific browser is used, just that there is one, they
can specify a dependency on www-browser
and allow the user to pick the
browser of their choice. The actual browser package has a section in the config
file that lists the virtual packages that it provides, in this case firefox
provides: www-browser iceweasel gnome-www-browser
. You can easily view what
virtual packages a package provides using apt-cache showpkg
:
$ apt-cache showpkg firefox
Package: firefox
Versions:
52.0.2+build1-0ubuntu0.12.04.1
[...]
Provides:
52.0.2+build1-0ubuntu0.12.04.1 - www-browser iceweasel gnome-www-browser
You can get a list of packages that provide a virtual package, shown in the
Reverse Provides
section, in the same way:
$ apt-cache showpkg www-browser
Package: www-browser
[...]
Reverse Provides:
w3m 0.5.3-5ubuntu1.2
chromium-browser 18.0.1025.151~r130497-0ubuntu1
konqueror 4:4.8.2-0ubuntu2
firefox 11.0+build1-0ubuntu4
[...]
Virtual packages are quite a powerful concept and allow for a significant amount of flexibility in building packages, a single package can supersede a handful of individual packages, without breaking backwards compatibility with older dependant projects.
Epoch Versions
I also had the pleasure of having to actually understand what the hell the
strings that pass for Debian package version numbers mean. Debian
deb-version
goes into the full details, but a quick overview wouldn’t hurt. The part of the
version string that burned me this time was the epoch
segment.
Take the version string from the Ubuntu 14.04 package for python-numpy
:
1:1.6.1-6ubuntu1
. This breaks down into epoch; upstream-version; debian-revision
or 1; 1.6.1; 6ubuntu1
. Epoch is this fun modifier that
allows the maintainer to basically reset the version numbers, by ignoring
anything of a lower epoch. Epoch defaults to 0
when not provided, so version
numbers are evaluated as expected.
If there is a major mishap in releases and the version numbers are beyond
recovery, the maintainer can increment the epoch version and essentially start
over– 1:1.0
evaluates as newer than 3.1.4
(implied 0 epoch so 0:3.1.4). At
a glance, without domain specific knowledge, this can lead to quite interesting
results when trying to figure out what version should be installed.
All in all, I feel like I have a better grasp of packaging as a whole from this experience, not just with Debian, but also the details that plague anyone attempting to maintain a consistent experience for downstream consumers.