Thoughts about Distutils and Debian
I'm currently trying to make up my mind how Distutils and building Debian packages fit together.
I have to impression we're faced with something like a chicken and egg problem. ...
Since not everybody knows the Debian package format, I'll give a short introduction:
A short story of .deb's and Debian packages -------------------------------------------
A .deb package is in fact really, really simple:
freefly;158> ar tv python-ldap_1.8-1_i386.deb rw-r--r-- 0/0 4 Nov 30 15:58 1999 debian-binary rw-r--r-- 0/0 1078 Nov 30 15:58 1999 control.tar.gz rw-r--r-- 0/0 52562 Nov 30 15:58 1999 data.tar.gz
freefly;159> ar x python-ldap_1.8-1_i386.deb
freefly;160> cat debian-binary 2.0
freefly;161> tar tvpzf control.tar.gz drwxr-xr-x root/root 0 1999-11-30 15:58:41 ./ -rwxr-xr-x root/root 553 1999-11-30 15:58:05 ./postinst -rwxr-xr-x root/root 461 1999-11-30 15:58:05 ./prerm -rw-r--r-- root/root 660 1999-11-30 15:58:41 ./md5sums -rw-r--r-- root/root 392 1999-11-30 15:58:41 ./control
freefly;162> tar tvpzf data.tar.gz drwxr-xr-x root/root 0 1999-11-30 15:58:04 ./ drwxr-xr-x root/root 0 1999-11-30 15:58:01 ./usr/ drwxr-xr-x root/root 0 1999-11-30 15:58:01 ./usr/lib/ drwxr-xr-x root/root 0 1999-11-30 15:58:01 ./usr/lib/python1.5/ ... -rw-r--r-- root/root 228 1999-11-30 15:48:07 ./usr/share/doc-base/python-ldap
The nice thing is that you can simply unpack the file with standard Unix tools. The same is true for the reverse: You can build a .deb with ar and tar only.
What's the stuff in control.tar.gz ? postinst and prerm (and preinst and postrm) are optional scripts that are called at various points of the installation/deinstallation of a package; control is a text file describing the package:
freefly;163> cat control Package: python-ldap Version: 1.8-1 Section: net Priority: optional Architecture: i386 Depends: libc6 (>= 2.1), libopenldap1 Installed-Size: 99 Maintainer: Gregor Hoffleit firstname.lastname@example.org Description: An LDAP module for Python. This module provides an Python interface to the LDAP client library (LDAP is the Lightweight Directory Access Protocol). It has been compiled with OpenLDAP.
Building a valid .deb package is as simple as
echo 2.0 >debian-binary vi control tar -c -z -f control.tar.gz ./control tar -c -z -f data.tar.gz -C build . ar cv my1stdeb-0.0.deb debian-binary control.tar.gz data.tar.gz
Now while this is a valid .deb file, there's more to a valid Debian package than this: Packages have to follow some rules in order to
(a) not to hose the system were they're unpacked (b) fit into the Debian archive scheme (c) support building from source (d) support auto-building from source
These rules are put together in the Debian Policy manual (http://www.debian.org/doc/debian-policy/) and the Debian Packaging manual.
The most interesting things in our context are certainly (c) and (d).
A valid Debian package should be built from a source package. A source package consists of a tarball of the upstream version (xyz_1.2.orig.tar.gz), a diff file with Debian's changes to the package (xyz_1.2-5.diff.gz) and a text file with a description of the package (xyz_1.2-5.dsc) including things like md5sums of the source files and GPG signed by the maintainer of the package. (If you have these three files, you can unpack the source tree with "dpkg-source -x xyz_1.2-5.dsc", or with
tar -xzpf xyz_1.2.orig.tar.gz zcat xyz_1.2-5.diff.gz | patch -p1
Debian's equivalent to an RPM spec file is a ./debian directory in the source tree. Typically, this directory looks like this:
freefly;193> cd python-ldap-1.8/ freefly;194> ls -ld debian/* -rw-r--r-- 1 flight flight 323 Mai 10 21:28 debian/README.Debian -rw-r--r-- 1 flight flight 203 Mai 10 21:28 debian/TODO.Debian -rw-r--r-- 1 flight flight 1644 Mai 10 21:28 debian/changelog -rw-r--r-- 1 flight flight 392 Mai 10 21:28 debian/control -rw-r--r-- 1 flight flight 799 Mai 10 21:28 debian/copyright -rw-r--r-- 1 flight flight 228 Mai 10 21:28 debian/doc-base -rw-r--r-- 1 flight flight 133 Mai 10 21:28 debian/postinst -rw-r--r-- 1 flight flight 130 Mai 10 21:28 debian/prerm -rwxr-xr-x 1 flight flight 1576 Mai 10 21:28 debian/rules*
The most important thing is debian/rules (note the connotation ;-), which is in fact an (executable) Makefile with targets "build", "clean", "binary-indep", "binary-arch" and "binary".
Provided the tools used in this rules Makefile are installed, building all packages from a source tree is done by calling
"debian/rules binary-indep" would build only the packages that are flagged architecture-independent (like a 100% pure Python package); "debian/rules binary-arch" would build the architecture-dependent packages for the architecture of the system we're running on (e.g. i386, m68k, sparc, hurd-i386 or perhaps bsd-i386 or cygwin-i386).
For a normal package, "rules build" calls "./configure; make", "rules clean" calls "make clean", "rules binary" calls "make DESTDIR='pwd'/debian/tmp install" and "dh_builddeb" (from a simplified view).
Needless to say that Debian's build tools (and autobuild daemon's) rely on the presence of ./debian/rules to build binary packages for every architecture from their source packages.
Enters Distutils ----------------
So where exactly does Distutils fit into this picture, how much sense makes bdist_deb, and what should it do ?
From the theory above, you see that it's possible and even quite easy to write a bdist_deb target that builds a valid .deb file (using ar and tar) for any Distutil'ed package. The problem is that that's still only a third-class Debian package: Fine for rapid-prototyping of .deb packages, but without support for Debian's infrastructure.
If we'd like to do better, we have to support debian/rules somehow. I'm still not sure what's the best way to do this, and how bdist's "source distributions" fit into this.
bdist_deb could create a source archive with a debian/rules skeleton that just works(tm). The debian/rules skeleton would just call up setup.py in different places. I.e. bdist_deb source distribution command creates a source package; this source package uses (in debian/rules) simple setup.py targets like "clean", "build" and "install" and finally builds the .deb file using standard Debian tools.
In an ideal world (any Distutil'ed package maps perfectly in a Debian package) this would be fine. In our world, Debian maintainers still would have to merge their changes with new upstream versions, therefore providing a debian/rules skeleton is perhaps not enough.
Maybe the bdist_deb binary distribution command then could simply call up "debian/rules binary" to build the binary packages.
A little bit more elaborated thoughts to come, I hope.