#! nix-shell script as systemd service?

Is there a way to use a #! /usr/bin/env nix-shell script as systemd service?

I tried the following setup:

❯ cat /etc/nixos/idle-shutdown.py
#! /usr/bin/env nix-shell
#! nix-shell -i python3 -p python3
import time
print('hello world')
time.sleep(10)

and in /etc/nixos/configuration.nix:

  systemd.services.idle-shutdown = {
    wantedBy = [ "multi-user.target" ];
    script = "${./idle-shutdown.py}";
    serviceConfig = {
      Restart = "always";
      RestartSec = 0;
    };
  };

But when I sudo nixos-rebuild switch, and check the logs I see that it fails:

❯ journalctl -f -u idle-shutdown.service
...
Aug 24 23:23:48 doodoo idle-shutdown-start[9434]: /usr/bin/env: ‘nix-shell’: No such file or directory

Is there a way to do this? Ultimately I’m just looking for a lightweight way to use a python script (potentially with some dependencies) as a systemd service.

2 Likes

Answering myself here: You can get pretty close to nix-shell shebangs with writePython3:

systemd.services.idle-shutdown = {
  description = "Shut down after being idle for some timeout.";
  serviceConfig = {
    ExecStart = "${pkgs.writers.writePython3 "idle-shutdown.py" { libraries = [ ]; } ''
      import time
      print("hello world")
      time.sleep(10)
    ''}";
    Restart = "always";
    RestartSec = "0";
  };
};

And additional packages can be placed in libraries.

1 Like

To answer the question from the subject.

Yes you can, you need to add nix to the units path like this:

systemd.services.idle-shutdown = {
    wantedBy = [ "multi-user.target" ];
    path = [ pkgs.nix ];
    script = "${./idle-shutdown.py}";
    serviceConfig = {
      Restart = "always";
      RestartSec = 0;
    };
  };
9 Likes