pythonpipsetuptoolsdistutils

Is there an idiomatic way to install systemd units with setuptools?


I'm distributing a module which can be imported and used as a library. It also comes with an executable—installed via console_scripts—for people to use.

That executable can also be started as a systemd service (Type=simple) to provide a daemon to the system.

systemd services need to refer to absolute paths in their ExecStart lines, so I need to figure out where the console_script got installed to.

With other build systemd like CMake, autotools or Meson, I can directly access the prefix and then use something like configure_file (meson) to substitute @PREFIX@ in foo.service.in, and then install the generated unit to $prefix/lib/systemd/system/.

I just can't figure out how to do this with setuptools. Inside setup.py, sys.prefix is set to python's prefix, which isn't the same thing. I have tried overriding install_data and install, but these approaches all have various problems like breaking when building a wheel via pip, or leaving the file around when uninstalling. (I'd be OK just not installing the service when we're not being installed system-wide; systemd wouldn't be able to find it if the prefix is not /usr or /usr/local anyway.)

Someone pointed me at a website which says that you're not supposed to do this with setuptools:

Note, by the way, that this encapsulation of data files means that you can't actually install data files to some arbitrary location on a user's machine; this is a feature, not a bug.

Which sounds like I'm just going against the grain here. I'm really looking for pointers or examples to tell me what I'm supposed to be doing here. If that's "don't use setuptools", fine - but then advice on what the preferred thing is would be welcome.


Solution

  • I would say don't use setuptools for this, it's not what it's made for. Instead use the package manager for the target distribution (apt, yum, dnf, pacman, etc.).

    I believe systemd and such things that are specific to the operating system (Linux distribution, Linux init system) are out of scope for Python packaging, pip, setuptools, etc. Keep as much as reasonably possible under setuptools's responsibility, so that the project stays pip-installable, and so that the project itself provides easy way to get access to systemd specific files but don't install them (maybe with a command my-thing-generate-systemd-files --target path/to/output for example, that would simplify the task for the users of the project). And on the other side provide Linux-distribution-specific packages (deb, rpm, etc.), if I am not mistaken there are tools that allow to build such packages starting from the Python project (a sdist or the source code repository).

    Some ideas (quick search without testing, not recommendations):