Monday, July 6, 2015

Backporting python-launchpadlib3 to Ubuntu 14.04

tl;dr; You can now use python 3 version of launchpadlib from ppa:zyga/launchpadlib-backports. Read on if you want to find out how I did it.

Today a colleague of mine asked for a small hint on how to do something with launchpadlib. I asked for the code sample and immediately stopped, seeing this is python 2 code. As python 2 is really not the way to start anything new in Ubuntu nowadays I looked at what's stopping us from using python 3.

It turns out, my colleague was using the LTS release (14.04) and python 3 version of launchpadlib just wasn't available at that time. Bummer.

Having a quick look at the dependencies I decided to help everyone out and create a PPA with the backported packages. Since this is a common process I though I would share my approach to both let others know and give more knowledgeable Debian developers a chance to correct me if I'm wrong.

The whole process starts with getting the source of the package you want to build. I wanted to get the latest and greatest packages so I grabbed the source package from Ubuntu 15.10 (wily). To do that I just go to packages.ubuntu.com and search for the right package. Here I wanted the python3-launchpadlib package. On the right-hand-side you can see the link to the .dsc file. You want that link so copy it now.

The right way to download each Debian source package is to use dget. Using a temporary directory as a workspace execute this command (if you read this later, the source package may not be available any more, you'd have to adjust the version numbers to reproduce the process).

dget http://archive.ubuntu.com/ubuntu/pool/main/p/python-launchpadlib/python-launchpadlib_1.10.3-2.dsc

With that package unpacked you want to change into the sub-directory with the unpackaged code. At this stage, you need to have a sbuild for Ubuntu 14.04. If you don't have one, it's time to make one now. You want to follow the excellent article on the Debian wiki for this. Many parts are just copy-paste but the final command you need to run is this:

sudo sbuild-createchroot --make-sbuild-tarball=/var/lib/sbuild/trusty-amd64.tar.gz trusty `mktemp -d` http://archive.ubuntu.com/ubuntu

Note that you cannot _just_ run it as there are some new groups you have to add and have available. Go read the article for that.

So with the sbuild ready to build our trusty packages, let's see what we get. Note, that in general, the process involves just those four steps.

  1. sbuild -d trusty
  2. dch # edit the changelog
  3. dpkg-buildpackage -S -sa
  4. dput ppa:zyga/launchpadlib-backports ../*.source.changes
After doing step one you'll see that you have missing build dependencies. Those are python-keyring, lazr.restfulclient, python-oauth and python-wadllib. We need to backport those too!

At this time the process recursively continues. You grab a .dsc file with dget it, and try to sbuild it right there. Luckily, you will find that nothing here has more dependencies and that each of the four packages builds cleanly.

At this time, you want to create a new PPA. Just go to your launchpad profile page and look for the link to create it. The PPA will serve as a buffer for all the packages so that we can finally build the package we are after. Without the PPA we'd have to build a local apt repository which is just mildly more difficult and not needed since we want to share our packages anyway.

With the PPA in place you can now start preparing each package for upload. As a habit I bump the version number and change the target distribution version from wily / unstable to trusty. I also add a changelog entry that explains this is a backport and mentions the name of the PPA. The version number is a bit more tricky. You want your packages to be different from any packages in the Ubuntu archive so that eventual upgrades work okay. The way I do that is to use a (x-).1 version which is always smaller than the corresponding x Ubuntu version. Let's see how this works for each of the packages we have here.
  • lazr.restfulclient has the Debian version 0.13.4-5 which I change to 0.13.4-5ubuntu0.1. This way both Ubuntu can upload 0.13.4-5ubuntu1 and Debian can upload 0.13.4-6 and users will get the correct update, nice.
  • python-keyring has the Ubuntu version 4.0-1ubuntu1 which I change to 4.0-1ubuntu1.1 so that the subsequent 4.0-1ubuntu2 can be uploaded to Ubuntu without any conflicts.
  • python-oauth has the Debian version 1.0.1-4 which I change to 1.0.1-4ubuntu0.1 to let Ubuntu update to -ubuntu1 eventually, if needed.
  • python-wadllib has the Debian version 1.3.2-3 which I change to 1.3.2-3ubuntu0.1 in exactly the same way.
Have a look at an example changelog to get a feel of how this all works together.

Now all the dependencies are ready and I can do the final test build of launchpadlib itself. Since I always test-build everything I will now need to expose access to my PPA so that my sbuild (which knows nothing about it otherwise) can get the missing packages and build everything. This is the magic line that does it:

sbuild -d trusty --chroot-setup-commands='apt-key adv --keyserver keyserver.ubuntu.com --recv-key E62E6AAB' --extra-repository "deb http://ppa.launchpad.net/zyga/launchpadlib-backports/ubuntu trusty main"

Here, we have two new arguments to sbuild. First, we use --chroot-setup-commands to import the public key that launchpad is using to sign packages in my archive. Note that the key identifier is unique to my PPA (and probably to my launchpad account). You want to check the key listed on the PPA page you got. The second argument --extra-repository just makes our PPA visible to the apt installation inside the chroot so that we can resolve all the dependencies. On more recent versions of Ubuntu you can also use [trusted=yes] suffix but this doesn't work for Ubuntu 14.04.

After all the uploads are done you should wait and see that all the packages are built and published. This is clearly visible in the "package details" link on the PPA. If you see a spinning stopwatch then the package is building. If you see a green cogwheel then the package has built but is not yet published into the PPA (those are separate steps, like make and make install, kind of). When all the packages are ready I copied all the binary packages (without rebuilding) from trusty to utopic, vivid and wily so that anyone can use the PPA. The wily copy is a bit useless but it should let users use the same instructions even if they don't need anything, without getting weird errors they might not understand.

So there you have it. The whole process took around an hour and a half (including writing this blog post). Most of the time was spent waiting on particular test builds and on the launchpad package publisher.

If you have any comments, hints or suggestions please leave them in the commends section below. Thanks.