Perkian - Chef

Written by Rich Morin.

Contents: (hide) (show)

Path:  AreasContentOverviews

Precis:  notes on using Chef to implement Perkian

Our current prototyping path (known as Perkify) concentrates on virtualization: creating Docker “containers” and/or Vagrant / Virtual Box “boxes”. Because the Docker and Vagrant ecosystems have a surfeit of tooling, we don’t need to use Chef for container generation, installation, etc. However, we may still opt to use it, for a couple of reasons.

First, virtualization isn’t appropriate for all of our use cases. For example, Docker isn’t even available for Android, which is an important target for us. It might also be too heavyweight an approach for (say) a cell phone or a Raspberry Pi. So, supporting “native” installation on multiple target platforms is clearly an important long-term objective. Chef cookbooks and/or recipes would let us handle this gracefully, dealing with the inevitable platform-specific “build” variations.

Second, because Chef can also delegate tasks to Docker (e.g., via the Docker Cookbook) or other package managers, we should be able to use Chef for all of our target distributions. However capable these tools might be, we’d rather not need to become expert in using all of them…


Chef cookbooks and recipes are fairly complex pieces of infrastructure; we certainly don’t want to large numbers of them. Still, we’d like Chef to provide a layer of abstraction between the list of packages and the required OS commands. So, our plan is to generate data files with the needed information, then have our Chef recipes read and act on them. Since we’re already using TOML in Pete’s Alley, it makes sense to encode the data in that format.


Let’s assume that we’re building a distribution based on Debian and that we wish to include the Atril package. All of the needed information can be harvested from the item’s main.toml and make.toml files. Indeed, we already have Elixir code in Pete’s Alley to generate control files (e.g., debian.toml) of the following form:

[ 'Atril' ]

  actions     = 'build, publish'
  package     = 'debi_pkgs|buster/atril'
  precis      = 'the official document viewer for MATE'
  title       = 'Atril'

A naive recipe for adding native packages to a Debian-based distribution might look something like this:

require 'toml'
items   = TOML.load_file('debian.toml')
keys    = items.keys.sort

keys.each do |key|
  item  = items[key]
  puts "#{ key } - #{ item['precis'] }"
  pkg_name  = item['package'].sub(%r{^.+/}, '')
  package pkg_name


In practice, things will be quite a bit more complicated. For example, there may be commands and/or recipes that will need to be run before or after the package installation. In some cases, such as GitHub repositories or RubyGems, there may not be a Debian package. We may also be creating containers that contain more than one package. Still, it should be possible to create appropriate recipes, assuming that we can find out what needs to be done.

To be continued…