fpm (eFfing Package Management) enables you to build all sorts of Linux packages with great ease and sanity.
Basically, ‘fpm’ allows you to deploy any software via OS packages, from an installation tree on disk or from already built artifacts specific to the chosen implementation language.
The main advantage over native tooling is you do not need to know about every minute detail of the involved commands and metafile formats for every platform. In case of Debian, that is at least the “control” and “rules” files, and tools like “buildpackage” and “debhelpers”.
‘fpm’ is written in Ruby and can thus be installed via
gem install. But you can also run it with JRuby in a JVM, that you might happen to already have on a host anyway. Using JRuny spares you the headache of juggling multiple Ruby versions and isolating gems against other Ruby applications.
If you package it up that way, it also can be installed on any Linux release because you only need a Java8 JRE installed to run it – no native code involved. You can use the
fpm.sh script in the priscilla project on GitHub to package ‘fpm’ with itself. As written, it works for Debian derivatives, but should be adaptable to other distros with a few changes (remember, ‘fpm’ makes that easy).
If you call
./fpm.sh pkg, the package contents is created in
build as a staging area, and when everything is ready,
fpm is called from within that staging area to create the final package:
build/opt_tools_fpm/opt/tools/fpm/bin/fpm \ -s dir -t deb -n opt-tools-fpm -v 1.11.0 \ --iteration 1 --category tools \ --deb-user root --deb-group root \ -m '"Juergen Hermann" <firstname.lastname@example.org>' \ --license 'See contained license, or homepage' \ --vendor github.com/jhermann/priscilla \ --description 'fpm helps you build packages quickly and easily' \ --url http://fpm.readthedocs.io/ \ --workdir $PWD/build/opt_tools_fpm/tmp \ -a all -d 'openjdk-8-jre|…|java8-runtime-headless' \ opt usr
Yes, this is a mouthful, but still shorter than a
.spec file, and easily adapted to other package managers.
The created DEB file
./build/opt_tools_fpm/opt-tools-fpm_1.11.0-1_all.deb has this metadata:
new debian package, version 2.0. size 23763108 bytes: control archive= 30446 bytes. 462 bytes, 12 lines control 119039 bytes, 1118 lines md5sums Package: opt-tools-fpm Version: 1.11.0-1 License: See contained license, or homepage Vendor: github.com/jhermann/priscilla Architecture: all Maintainer: "Juergen Hermann" <email@example.com> Installed-Size: 27046 Depends: openjdk-8-jre|zulu8|…|java8-runtime-headless Section: tools Priority: extra Homepage: http://fpm.readthedocs.io/ Description: fpm helps you build packages quickly and easily
The major part of files is installed into
/opt/tools/fpm, but a symlink at
/usr/bin/fpm makes the command available on the path.
Building fpm 1.11.0 that way was tested on Ubuntu Bionic with openjdk-8-jre-headless 8u242.
There are a lot of source and target types available in fpm (dir, gem, deb, npm, rpm, tar, cpan, pear, empty, puppet, python, osxpkg, solaris, p5p, pkgin, freebsd, apk, snap, pleaserun, zip, virtualenv, pacman, sh), this example converts a Python workdir into a DEB package file.
The rudiments project serves as the example here, but you can use any pure Python project built with setuptools. You have to clone the project and then call fpm like so:
( deactivate 2>/dev/null; py=/usr/bin/python3; \ fpm -s python -t deb --category python \ --python-bin $py \ --python-pip "$py -m pip" \ --python-package-name-prefix "$(basename $py)" \ --python-obey-requirements-txt \ --python-install-data "/usr/local/share/$(basename $py)/$($py ./setup.py --name)" \ -m "\"$($py ./setup.py --author)\" <$($py ./setup.py --author-email)>" \ --vendor "$($py ./setup.py --url | cut -f3-4 -d/)" \ --force $PWD/setup.py )
--force option overwrites an existing package file, so you can call the command multiple times without an error.
If you inspect the built package with
dpkg-deb -I python3-rudiments_*_all.deb, this is the output:
new Debian package, version 2.0. size 31062 bytes: control archive=1417 bytes. 366 bytes, 12 lines control 3789 bytes, 30 lines md5sums Package: python3-rudiments Version: 0.3.1 License: Apache 2.0 Vendor: github.com/jhermann Architecture: all Maintainer: "Jürgen Hermann" <firstname.lastname@example.org> Installed-Size: 79 Depends: python3-requests (>= 2.6) Section: python Priority: extra Homepage: https://github.com/jhermann/rudiments Description: Rudiments – Fundamental elements for any Python project.
The package's content is placed into these directories:
/usr/local/lib/python3.6 /usr/local/share/python3/rudiments /usr/share/doc/python3-rudiments
You can install it using
dpkg -i … and then do a quick import test with this command:
python3 -c "import rudiments; print(rudiments)"
fpm is available on GitHub.
Credits: Package icon by Breathe Icon Team: Sebastian Porta, Cory Kontros, Andrew Starr-Bochicchio