From 8335076173d2fd83a9bc13134d554255a527a8aa Mon Sep 17 00:00:00 2001 From: Profpatsch Date: Sat, 16 Mar 2024 22:33:20 +0100 Subject: feat(users/Profpatsch): add shortcuttable Initial mockup for a tool which restarts its subprocess on SIGHUP, and stops everything on SIGTERM and SIGINT. Change-Id: Ie5260d73c2663d1821eb6623e2bc61d16f6c92cd Reviewed-on: https://cl.tvl.fyi/c/depot/+/11168 Autosubmit: Profpatsch Reviewed-by: Profpatsch Tested-by: BuildkiteCI --- users/Profpatsch/shortcuttable/default.nix | 172 +++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 users/Profpatsch/shortcuttable/default.nix (limited to 'users') diff --git a/users/Profpatsch/shortcuttable/default.nix b/users/Profpatsch/shortcuttable/default.nix new file mode 100644 index 0000000000..13ba220400 --- /dev/null +++ b/users/Profpatsch/shortcuttable/default.nix @@ -0,0 +1,172 @@ +{ depot, lib, pkgs, ... }: + +let + # run prog... and restart whenever SIGHUP is received + # + # this is useful for binding to a shortcut. + # + # Unfortunately, this requires a bunch of workarounds around the semantics of `trap`, + # but the general idea of bundling subprocesses with `setsid` is somewhat sound. + runShortcuttable = + depot.nix.writeExecline "run-shortcuttable" { } [ + "importas" + "-i" + "run" + "XDG_RUNTIME_DIR" + "if" + [ "mkdir" "-p" "\${run}/shortcuttable/test" ] + "getpid" + "-E" + "controlpid" + savePid + "\${run}/shortcuttable/test/control" + "$controlpid" + + # start the program + "background" + [ + startSaveSID + "\${run}/shortcuttable/test/running-sid" + "$@" + ] + + "trap" + [ + "SIGHUP" + [ + "if" + [ "echo" "got hup" ] + "if" + [ + "if" + [ "echo" "killing our child processes" ] + "envfile" + "\${run}/shortcuttable/test/running-sid" + "importas" + "-ui" + "child_sid" + "pid" + "foreground" + [ "ps" "-f" "--sid" "$child_sid" ] + ctrlCCtrlDSid + "$child_sid" + ] + "if" + [ "echo" "restarting into" "$@" ] + "background" + [ + startSaveSID + "\${run}/shortcuttable/test/running-sid" + "$@" + ] + ] + "SIGTERM" + [ + (killShortcuttable { signal = "TERM"; }) + "\${run}/shortcuttable/test/running-sid" + "\${run}/shortcuttable/test/exit" + ] + "SIGINT" + [ + (killShortcuttable { signal = "INT"; }) + "\${run}/shortcuttable/test/running-sid" + "\${run}/shortcuttable/test/exit" + ] + ] + depot.users.Profpatsch.execline.setsid + "child_sid" + "getpid" + "-E" + "exitpid" + savePid + "\${run}/shortcuttable/test/exit" + "$exitpid" + "sleep" + "infinity" + ]; + + killShortcuttable = { signal }: depot.nix.writeExecline "kill-shortcuttable" { readNArgs = 2; } [ + "if" + [ "echo" "got SIG${signal}, quitting" ] + "if" + [ + "envfile" + "$1" + "importas" + "-ui" + "child_sid" + "pid" + "foreground" + [ "ps" "-f" "--sid" "$child_sid" ] + ctrlCCtrlDSid + "$child_sid" + ] + "if" + [ "echo" "killing shortcuttable loop" ] + "envfile" + "$2" + "importas" + "-ui" + "trap_pid" + "pid" + "foreground" + [ "ps" "-fp" "$trap_pid" ] + "kill" + "--signal" + signal + "$trap_pid" + ]; + + savePid = depot.nix.writeExecline "save-pid" { readNArgs = 2; } [ + "if" + [ "echo" "saving process:" ] + "if" + [ "ps" "-fp" "$2" ] + "if" + [ + "redirfd" + "-w" + "1" + "$1" + "printf" + "pid = %s\n" + "$2" + ] + "$@" + ]; + + # try to kill process, first with SIGTERM then SIGQUIT (in case it’s a repl) + ctrlCCtrlDSid = depot.nix.writeExecline "ctrl-c-ctrl-d" { readNArgs = 1; } [ + "ifelse" + "-n" + [ "kill" "--signal" "TERM" "--" "-\${1}" ] + [ + "if" + [ "echo" "could not kill via SIGTERM, trying SIGQUIT …" ] + "ifelse" + "-n" + [ "kill" "--signal" "QUIT" "--" "-\${1}" ] + [ "echo" "SIGQUIT failed as well, keeping it running" ] + "$@" + ] + "$@" + ]; + + startSaveSID = depot.nix.writeExecline "start-save-sid" { readNArgs = 1; } [ + depot.users.Profpatsch.execline.setsid + "child_sid" + "importas" + "-ui" + "child_sid" + "child_sid" + "if" + [ "echo" "children sid:" "$child_sid" ] + savePid + "$1" + "$child_sid" + "$@" + ]; + + +in +runShortcuttable -- cgit 1.4.1