Building with FPM

17 Aug 2016 in TIL

We build RPMs for all of our internal projects at DataSift, which means that we end up writing (or more likely, copying) an RPM spec file in to each project. Some of our build tools use FPM to build themselves, and I figured it was worth a look.

Imagine that we have a project name shinything. I've simplified our actual project layout a lot, but at it's core it looks like the following:

bash
.
├── resources
├── src
│   ├── application
│   │   ├── controller
│   │   │   └── IndexController.php
│   │   ├── model
│   │   │   └── User.php
│   │   └── view
│   │   └── show-user.php
│   ├── composer.json
│   ├── composer.lock
│   ├── config
│   │   ├── mappings.json
│   │   └── targets.json
│   └── public
│   └── index.php
└── test

From this, we want everything in the src folder to be in our RPM package, making sure that the test and resources folders never make it to production. We want to install the application to /var/www/shinything and it's config to /etc/shinything.

The first thing we need to do is to tell fpm that we want to build from a directory, we want an RPM as our output and that our RPM should be called "shinything".

bash
fpm -s dir -t rpm -n shinything

Next, we need to map the files on disk to their location once installed. To do this, you use the source=dest option

bash
fpm -s dir -t rpm -n shinything src/=/var/www/shinything

This means that everything in src will be installed to /var/www/shinything. The / after src is important, as it means use everything inside that directory, without using that directory itself.

As well as the application, we need to install the config files we need to /etc/shinything. We can add another source=dest option to do this:

bash
fpm -s dir -t rpm -n shinything src/=/var/www/shinything src/config/=/etc/shinything

We want to mark anything in /etc as a config file so that they are not overwritten when we update our RPM if there are local changes:

bash
fpm -s dir -t rpm -n shinything --config-files /etc --exclude src/config src/=/var/www/shinything src/config/=/etc/shinything

Finally, we want to remove the config files from /var/www/shinything/config so that people don't mistakenly use them. To do this, we can use the exclude filter. Be careful not to add a leading slash or it won't match.

bash
fpm -s dir -t rpm -n shinything --config-files /etc --exclude "var/www/shinything/config*" src/=/var/www/shinything src/config/=/etc/shinything

At this point, we've created the perfect RPM!

bash
$ fpm -s dir -t rpm -n shinything --config-files /etc --exclude "var/www/shinything/config*" src/=/var/www/shinything src/config/=/etc/shinything
Created package {:path=>"shinything-1.0-1.x86_64.rpm"}

If we take a look inside this RPM using the rpm tool, it will list everything that will be installed.

bash
$ rpm -qlp shinything-1.0-1.x86_64.rpm
/etc/shinything/mappings.json
/etc/shinything/targets.json
/var/www/shinything/application/controller/IndexController.php
/var/www/shinything/application/model/User.php
/var/www/shinything/application/view/show-user.php
/var/www/shinything/composer.json
/var/www/shinything/composer.lock
/var/www/shinything/public/index.php