Continuing the discussion from How to add local files into nginx derivation for nix-shell?:
Here’s the slightly modified shell.nix
from the post linked above (with a couple more questions in tow):
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
let
nginx-with-config = pkgs.writeScriptBin "my_nginx" ''
# VVVV
exec ${pkgs.nginx}/bin/nginx -c ${./nginx.conf} "$@"
# ^^^^
'';
in mkShell {
name = "my-shell";
buildInputs = [
nginx-with-config
];
shellHook = ''
my_nginx
trap "my_nginx -s quit" EXIT
'';
}
1. Why use exec
?
The Nix expression works even after deleting exec
. Are there any benefits?
2. Are commands in a shellHook
executed in the same shell created by the Nix expression?
When exec
is invoked with a command, “it replaces the shell without creating a new process”. For example, running
exec watch -n 1 "ls -al"
would replace the current shell, and CTRL+C would simply close the terminal window (e.g., in tmux
).
Now, running the Nix expression above with nix-shell
will drop into an interactive shell where nginx
is already running, instead of my_nginx
“consuming” the current shell. trap
wouldn’t even have a chance to run, and yet it does because nginx
will get shut down upon exit from the Nix shell. nginx
will fork itself in the background (is that the right way to say it?) so this may changes things, and in this case my ignorance is more about Linux than Nix itself.
I thought that this is a sign that each command is being run in a new shell, but this may not be the case because the trap
command works too, and if that would run in its own shell, then it would trap it’s own exit, and nginx
would be stopped right after starting up. the nginx
executable will fork itself in the background (not sure what the right way to say this).
Anyway, currently I see that shellHook
working only if these commands are simply dropped into the newly generated Nix shell, because the alternative (where each commands will run in its own shell) doesn’t make sense,
bash -c 'my_nginx"'; bash -c 'trap "my_nginx -s quit" EXIT'
because the trap
would simply detect the exit of its own shell (and shut down the newly started nginx
instance right away).