How to create module that can configure file at hardcoded path?

I am trying to package a C program mqtt-arp, as a learning exercise.
It is in this Github project: GitHub - u1f35c/mqtt-arp: Simple tool to watch for ARP presence via Netlink and report using MQTT

This program uses a configuration file that it reads from /etc/mqtt-arp.conf and this path is not configurable as command line argument.

In my package derivation I do

  postPatch = ''
    substituteInPlace mqtt-arp.c \
       --replace "/etc/mqtt-arp.conf" "$out/etc/mqtt-arp.conf"
  '';

  installPhase = ''
    make install DESTDIR=$out
  '';

which I think is the right approach?

But I am also trying to create a module for it (my first) for where the contents of the file can be configured. Here I get stuck. Since the program is not prepared to read the file name as argument, it seems I must modify the original file. I don’t think that is possible from a module, right? Is there a way to do this? Perhaps there is a similar type of problem solved that I can look at?

(The program also has command line options but I want to understand if I can use the configuration file)

1 Like
  1. Request this as a feature!
  2. If you haven’t already, make this overridable, eg by following the callPackage idom
  3. Make the “config” an argument to the argumentset with a default of null
  4. If nothing (or null) has been passed use the default config from out, the passed one otherwise

A draft:

{ config ? null, … }:

let effectiveConfig = if config == null then "$out/etc/mqtt-arp.conf" else config; in
… {
  postPatch = ''
    substituteInPlace mqtt-arp.c \
       --replace "/etc/mqtt-arp.conf" "${effectiveConfig}"
  '';

  # …
}
1 Like

That’s useful! I didn’t know about this pattern. On a balance, it is perhaps better to take advantage of the command line parameters in my case, since a module that uses this cannot take advantage of a package cache easily? But in cases when that is not possible, this pattern is gold. Thank you!