126 lines
2.9 KiB
Nix
126 lines
2.9 KiB
Nix
{
|
|
socat,
|
|
writeShellScriptBin,
|
|
shellId,
|
|
cli,
|
|
timeout,
|
|
...
|
|
}:
|
|
let
|
|
wait = builtins.toString timeout;
|
|
in
|
|
{
|
|
daemon = writeShellScriptBin "ides-monitor-${shellId}" ''
|
|
BASE_PATH="$1"
|
|
SOCKET=/run/user/$(id -u)/ides-${shellId}.sock
|
|
|
|
# if socket exists, it's already being monitored
|
|
if [ -e "$SOCKET" ]; then
|
|
exit 1
|
|
fi
|
|
|
|
PIDS=()
|
|
|
|
# loop on socket forever
|
|
while true; do
|
|
# wait to receive a PID
|
|
PID=$(timeout ${wait} ${socat} UNIX-LISTEN:"$SOCKET" -)
|
|
# if received and unique, add to our watch
|
|
if [ "$?" -eq 0 ] && ! [[ "''${PIDS[@]}" =~ $PID ]]; then
|
|
echo adding $PID to watch
|
|
PIDS+=($PID)
|
|
echo pids are now ''${PIDS[@]}
|
|
fi
|
|
|
|
# check process statuses
|
|
DEAD=true
|
|
for INDEX in "''${!PIDS[@]}"; do
|
|
REMOVE=false
|
|
|
|
# get pid
|
|
CHECK="''${PIDS[$INDEX]}"
|
|
echo checking $CHECK
|
|
|
|
# check status
|
|
ALIVE=$(kill -0 "$CHECK" 2>&1 > /dev/null)
|
|
|
|
# determine eligibility to act as a service root
|
|
if $ALIVE; then
|
|
|
|
CMD=$(cat /proc/$CHECK/comm)
|
|
case "$CMD" in
|
|
# if host is an editor, we don't care about pwd
|
|
code|codium|zed|emacs|intellij*|sublime*)
|
|
DEAD=false
|
|
;;
|
|
# if it's a shell we really do
|
|
sh|bash|zsh|fish|nu|murex|*)
|
|
DIR=$(readlink /proc/$CHECK/cwd)
|
|
if [[ "$DIR" == "$BASE_PATH"* ]]; then
|
|
DEAD=false
|
|
else
|
|
REMOVE=true
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
echo found $CHECK alive with $CMD in $DIR
|
|
|
|
else
|
|
|
|
echo found $CHECK dead
|
|
|
|
REMOVE=true
|
|
|
|
fi
|
|
|
|
if $REMOVE; then
|
|
echo removing ineligible pid $CHECK
|
|
unset "PIDS[$INDEX]"
|
|
fi
|
|
|
|
done
|
|
|
|
if "$DEAD"; then
|
|
echo no live pids, breaking
|
|
break
|
|
fi
|
|
|
|
done
|
|
|
|
# loop has broken, no valid pids left
|
|
echo stopping all!
|
|
${cli} stop
|
|
'';
|
|
|
|
# FIXME if the client finds its parent is an editor process,
|
|
# such as `code`, should it keep walking pids until the final parent?
|
|
client = writeShellScriptBin "ides-notify-${shellId}" ''
|
|
function get-parent() {
|
|
ps --no-header -o ppid:1 $1
|
|
}
|
|
|
|
function get-command() {
|
|
cat /proc/$1/comm
|
|
}
|
|
|
|
SOCKET=/var/run/user/$(id -u)/ides-${shellId}.sock
|
|
# wait for socket to come up
|
|
while ! [ -e "$SOCKET" ]; do
|
|
sleep 0.5
|
|
done
|
|
|
|
# check if our calling shell's parent process is direnv
|
|
PARENT=$(get-parent $1)
|
|
COMM=$(get-command $PARENT)
|
|
TARGET="$1"
|
|
echo found $COMM as parent
|
|
if [[ "$COMM" == "direnv" ]]; then
|
|
# if so, skip up another parent to get the process it is exporting to
|
|
TARGET=$(get-parent $PARENT)
|
|
fi
|
|
# tell monitor about the devshell
|
|
echo "$TARGET" | ${socat} - UNIX-CONNECT:"$SOCKET"
|
|
'';
|
|
}
|