Why only `writeScriptBin` works for this derivation? (+ general questions about `write*` functions)

Continuing the discussion from How to add local files into nginx derivation for nix-shell?:

Starting another thread about this example, because I keep having questions:

{ pkgs ? import <nixpkgs> {} }:
with pkgs;

let
  nginx-with-config = pkgs.writeScriptBin "my_nginx" ''
    exec ${pkgs.nginx}/bin/nginx -c ${./nginx.conf} "$@"
  '';

in mkShell {
  name = "my-shell";
  buildInputs = [
    nginx-with-config 
  ];

  shellHook = ''
    my_nginx
  '';
}

Based on the docs, I would believe that the “bin” part is irrelevant, and the only thing that matters is that the text saved into the Nix store is made executable.

For example, re-writing the above example in its most general form will work too,

  nginx-with-config =
    pkgs.writeTextFile {
      name = "my_nginx";
      text = ''
        exec ${pkgs.nginx}/bin/nginx -c ${./nginx_conf} "$@"
      '';
      executable = true;
      destination = "/bin/my_nginx";
    }
  ;

but if the “bin” is dropped,

  nginx-with-config = pkgs.writeScript "my_nginx" ''
    exec ${pkgs.nginx}/bin/nginx -c ${./nginx.conf} "$@"
  '';

# or

  nginx-with-config =
    pkgs.writeTextFile {
      name = "my_nginx";
      text = ''
        exec ${pkgs.nginx}/bin/nginx -c ${./nginx_conf} "$@"
      '';
      executable = true;
      destination = "/my_nginx";
    }
  ;

then the derivation still gets built, but the shellHook will fail with something like

nginx: invalid option: "/nix/store/84yc8imyhsx6fq3wc90v6pvmcrdmc5r6--my_nginx

I guess the issue is that when the “bin” versions are used, the I can refer to the script by name, but otherwise I would have to use the full Nix store path?


For future self:

If you inspect the PATH in the shell this should make some sense. Marking it executable is all you need to execute it, but it’s <package>/bin/ that ends up added to PATH.

2 Likes

This was the crucial information I was missing, thanks.

1 Like