Skip to content

realtime-neil/ros-bloom-debhelper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ros-bloom-debhelper

bloom your ROS projects with the full power of debhelper.

tldr

$ tree ~/my_catkin_ws
/home/user/my_catkin_ws
`-- src
    `-- my_project
        |-- CMakeLists.txt
        |-- debian
        |   |-- TODO.em
        |   |-- control.em
        |   |-- cron.daily.em
        |   |-- logrotate.em
        |   |-- postinst.em
        |   |-- postrm.em
        |   |-- rules.em
        |   |-- service.em
        |   `-- udev.em
        |-- etc
        |   `-- rsyslog.d
        |       `-- 99-slug.conf.in
        |-- launch
        |   `-- main.launch
        |-- package.xml
        `-- src
            `-- main.cpp

$ bloom-release --rosdistro melodic ...
...
$ # checkout release, gbp buildpackage
...
$ dpkg-deb --raw-extract ../ros-melodic-my-project_0.0.1_amd64.deb ./raw
$ tree ./raw
./raw
|-- DEBIAN
|   |-- conffiles
|   |-- control
|   |-- md5sums
|   |-- postinst
|   |-- postrm
|   |-- preinst
|   `-- prerm
|-- etc
|   |-- cron.daily
|   |   `-- ros-melodic-my-project
|   |-- logrotate.d
|   |   `-- ros-melodic-my-project
|   `-- rsyslog.d
|       `-- 99-ros-melodic-my-project.conf
|-- lib
|   |-- systemd
|   |   `-- system
|   |       `-- ros-melodic-my-project.service
|   `-- udev
|       `-- rules.d
|           `-- 60-ros-melodic-my-project.rules
|-- opt
|   `-- ros
|       `-- melodic
|           |-- lib
|           |   |-- my_project
|           |   |   `-- my-project
|           |   `-- pkgconfig
|           |       `-- my_project.pc
|           `-- share
|               `-- my_project
|                   |-- cmake
|                   |   |-- my_projectConfig-version.cmake
|                   |   `-- my_projectConfig.cmake
|                   |-- launch
|                   |   `-- main.launch
|                   `-- package.xml
`-- usr
    `-- share
        `-- doc
            `-- ros-melodic-my-project
                |-- TODO.Debian
                `-- changelog.Debian.gz

What?

You can bloom your ROS project (that thing you build with catkin) into a Debian package archive (*.deb) that installs one (or more) of the following:

Why?

Because you're a Debian package maintainer and you want to do one (or more) of the following:

  • run your ROS application as a systemd service
  • use udev to detect and configure new/custom/unusual hardware
  • rotate logs generated by your ROS application
  • run your ROS application from a cron script
  • include a bespoke license
  • more coming soon

How?

Within your ROS project directory (where you keep the CMakeLists.txt and package.xml), create a debian directory. Put your debhelper-compatible files in there. Here's a sampling, showing where each lands after installation:

catkin_ws/src/my_project/debian/TODO       -> /usr/share/doc/ros-${ROS_DISTRO}-my-project/TODO.Debian
catkin_ws/src/my_project/debian/cron.daily -> /etc/cron.daily/ros-${ROS_DISTRO}-my-project
catkin_ws/src/my_project/debian/logrotate  -> /etc/logrotate.d/ros-${ROS_DISTRO}-my-project
catkin_ws/src/my_project/debian/service    -> /lib/systemd/system/ros-${ROS_DISTRO}-my-project.service
catkin_ws/src/my_project/debian/udev       -> /lib/udev/rules.d/60-ros-${ROS_DISTRO}-my-project.rules

Huh?

There are really two mechanisms enabling this trick. The first is the manner by which bloom populates the debian directory of the released package. The second is the fallback behavior in debhelper.

How does bloom populate the debian directory?

As of bloom 0.5.13, you can supply files in a "debian" folder in your package, and the various debhelpers, including dh_installudev will pick them up.

-- mikepurvis, answering himself, https://answers.ros.org/question/133966/install-directly-to-etcudevrulesd/?answer=212041#post-id-212041

As of this writing, the latest release of bloom is 0.8.0 (c247a13) and the mechanism to which mikepurvis alludes is implemented within bloom/generators/debian/generator.py, in and around the function place_template_files:

https://github.com/ros-infrastructure/bloom/blob/c247a1320172867ce87c94939df1f166d25a0bb0/bloom/generators/debian/generator.py#L838

During the execution of bloom-release, place_template_files will copy the debian directory from the catkin project (thing being bloomed) to the "Debianized release" (thing being generated). The copied contents are combined with various templates and then the process of template expansion begins.

Template files have a *.em suffix and any *.em file found in the debian directory will be expanded using empy. For each template file, empy replaces any variable reference with the associated value and writes the expanded result into the .em-suffix-stripped filename. For example, a template foobar.txt.em would be empy-expanded to produce foobar.txt. bloom-generate explicitly defines the set of variable-value pairs empy will use. The following is a partial enumeration of those variables:

  • @(Copyright)
  • @(DebianInc)
  • @(Description)
  • @(Distribution)
  • @(Homepage)
  • @(InstallationPrefix)
  • @(Maintainer)
  • @(Package)

bloom-generate tacitly assumes you will use debhelper to build your Debian packages --- it uses a debian/rules.em template that explicitly invokes dh. In any case, the resulting expansions are committed to the "release" (almost always a bare git repository) from which the Debian packages can be built.

How does debhelper find files?

When debhelper goes looking for files, it searches under the debian directory. Some of these files are required. Other files are optional. For most of the optional files, each has within its basename (usually as package. prefix) the name of the package to which it belongs. Consider the following examples for the fictitious package foo:

  • debian/foo.init: init script, installs to /etc/init.d/foo
  • debian/foo.cron.hourly: hourly cron job, installs to /etc/cron.hourly/foo

Additionally, and crucially, debhelper also uses other files:

Note for the first (or only) binary package listed in debian/control, debhelper will use debian/foo when there's no debian/package.foo file. However, it is often a good idea to keep the package. prefix as it is more explicit. The primary exception to this are files that debhelper by default installs in every binary package when it does not have a package prefix (such as debian/copyright or debian/changelog).

-- http://man7.org/linux/man-pages/man7/debhelper.7.html, "Debhelper Config Files" section

This association to an implicit package name is useful when, say, you don't actually know the name of the package for which you want to install artifacts. This is exactly the case for ROS packages targeting a Debian-like OS. The Debian package name is of the form ros-${ROS_DISTRO}-catkin-project and the ${ROS_DISTRO} could be one of several identifiers through which bloom-release iterates. The quantity and nature of package names is known to the maintainer only after the bloom succeeds.

Caveats?

  • In the case where you have both a debian/foo and a debian/foo.em, the expansion of the latter overwrites the former.

  • The example rsyslog filter rule file is a cmake trick, not a debhelper trick. It's there to illustrate how such a thing would interact with dh_logrotate.

Credits

This repository was borne out of a question I asked on ROS Answers: https://answers.ros.org/question/331528/how-to-bloom-with-init-system-integration/

Thanks to @mikepurvis who, back in 2014, asked --- and then answered --- the question about the proper way to install a udev rules file.

Thanks to @gvdhoorn, both for pointing me toward the already-answered questions relevant to mine, and for discussing various shortcomings inherent to my approach.

Thanks to @nuclearsandwich for the insight into, and explanations for, some little-known ROS package conventions.