Building Debian Packages with Python (UPDS Part I.V)

I use DPKGs for all my deployments, and have tried a number of tools to build them. None have been perfect though, so what’s the best solution? Build my own, of course! TL;DR: I wrote a native Python (OS-independent) package to build Debian Packages: deb‑constrictor.

Alternatives

I’ve tried a few ways of making DPKGS, and none have been quite right for me.

FPM

Brilliant tool for creating packages of different types (DEB, RPM, OS X packages, etc), and really simple to get something going. However, it did not have the customisability I needed, for example, permissions for specific files or the ability to define symlinks. This was important to me because instead of being able to define a symlink to the sites-enabled directory for NGINX/Apache, I had to write the config file directly into it, which is Not Right.

gradle-ospackage-plugin

A plugin for Gradle that builds DEBs and RPMs. It is relatively simple to get going, but has a few bugs. For example, if you don’t provide dependencies for your package, it will automatically specify java as a dependency. I got around this by specifying python as a dependency, assuming that all my projects would require python, but still a slight weirdness.

One of the more serious reasons that I wanted to move away from Gradle was a bug regarding maintainer scripts which meant that they were only being executed on install (this bug is still open at the time of writing).

Maven

As I’ve written before, the 800 pound gorilla of dependency management. Maybe one day I’ll dive in, but today is not it.

Using constrictor

First, pip install deb-constrictor. Building a package is easy, just specify your project name, architecture, source/destination directories, symlinks, dependencies, and maintainer script paths. Here’s how to build the package for this website:

from constrictor import DPKGBuilder


dirs = [
    {
        'source': '~/python/beneboyit/frontend/src',
        'destination': '/srv/python/bbit-web-frontend',
        'uname': 'www-data'
    }
]

maintainer_scripts = {
    'postinst': '~/python/beneboyit/frontend/scripts/after-install',
    'preinst': '~/python/beneboyit/frontend/scripts/before-install'
}

links =  [
    {
        'source': '/etc/nginx/sites-enabled/bbit-web-frontend',
        'destination': '../sites-available/bbit-web-frontend'
    },
    {
        'source': '/etc/uwsgi/apps-enabled/bbit-web-frontend.ini',
        'destination': '../apps-available/bbit-web-frontend.ini'
    },
]

depends = ('nginx', 'uwsgi')

output_directory = '~/build'

d = DPKGBuilder(output_directory, 'bbit-web-frontend', '1.5', 'all', dirs, links, maintainer_scripts)
d.build_package()

constrictor will follow the convention of naming the package project‑name_version_architecture.deb and putting it inside the output_directory. Alternatively, provide a name for your package as the output_name argument, and the package will be created with this name in the output_directory.

Conclusion

I’m half a step closer to my Ultimate Python Deployment System, stay tuned for updates.

Previous entry

Next entry

Related entries

Deb Constrictor for Configuration Deployment (Part 3)   |   Deb Constrictor for Application Deployment (Part 1)   |   The Ultimate Python Deployment System I