Hi,
I am trying to package my first program with Nix. It is called wg-netns (GitHub - dadevel/wg-netns: WireGuard with Linux Network Namespaces) and it contains code to call external commands (such as the “ip” command) by calling subprocess.run(). This does not work and I wonder how I can best adjust it to work on NixOS?
From the source code of it:
def ip(*args, stdin: str = None, check=True, capture=False) -> str:
return run('ip', *args, stdin=stdin, check=check, capture=capture)
def host_eval(*args, stdin: str = None, check=True, capture=False) -> str:
return run(SHELL, '-c', *args, stdin=stdin, check=check, capture=capture)
def run(*args, stdin: str = None, check=True, capture=False) -> str:
args = [str(item) if item is not None else '' for item in args]
if VERBOSE:
print('>', ' '.join(args), file=sys.stderr)
process = subprocess.run(args, input=stdin, text=True, capture_output=capture)
if check and process.returncode != 0:
error = process.stderr.strip() if process.stderr else f'exit code {process.returncode}'
raise RuntimeError(f'subprocess failed: {" ".join(args)}: {error}')
return process.stdout
Then you need to make sure that it is either in the PATH of the unit (systemd.services.<name>.path) or a proper dependency of the python program by wrapping it using wrapProgram.
If those are a hard requirement for the software to work you must ensure they are available, and preferably not load them impurely from the environment. You have a few options:
Create patches that add @command@ placeholders and the run substituteAll to replace them with the appropriate path during the build.
(works for every software, not just python modules, but it’s quite a burden to maintain)
Alternatively, use substituteInPlace or sed to do the replacing manually.
(less annoying but you have to be careful not to mess up the source)
Python programs are always wrapped, so you can exploit this to add the packages you need to the PATH. Add this to the buildPythonPackage arguments: makeWrapperArgs = [ "--prefix PATH : ${lib.makeBinPath [ ... ]}" ];
(this is probably the best option)
Thanks for good suggestions. I think I like option 3 best. The program is usually run using the systemd service, but proper packaging needs to handle both ways, I think (using service or invoked directly)
I am trying to do the same but for a python module, i.e. makeWrapperArgs cannot be used. The module calls swig and gfortran. Is there no other way than to patch, in order to make them available? I see that the patches have to be updated each time the module version is bumped.
Can you point to an example in <nixpkgs> where option 1 is used, so I can get an idea of how to do it?