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.