-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathinotify-run
executable file
·157 lines (133 loc) · 3.14 KB
/
inotify-run
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/bash
# Wrapper around inotifywait for easier usage.
usage() {
echo "$0 <inotifywait-args>... -- <cmd>..."
}
inotifywait_args=()
while [[ -n "$1" && "$1" != "--" ]]; do
inotifywait_args+=("$1")
shift
done
if [[ "$1" != "--" ]]; then
echo "Missing command." >&2
usage
exit 64
fi
shift
cmd=("$@")
title() {
printf '\e]1;%s\a' "$*"
printf '\e]2;%s\a' "$*"
}
# A FIFO to communicate the child pid from the sub-shell.
child_pid_pipe=$(mktemp --dry-run)
mkfifo "$child_pid_pipe"
wrapper_pid=
# Required to "wait" in EXIT handler, where pid is not considered to be part of
# the shell with "wait" anymore.
wait_for_pid() {
pid="$1"
if ! kill -0 "$pid" 2>/dev/null; then
return 0
fi
echo -n "Waiting for $pid to terminate" >&2
while kill -0 "$pid" 2>/dev/null; do
echo -n '.' >&2
sleep 0.5 || break
done
echo >&2
}
kill_child() {
pid="$1"
# Send SIGTERM after 3s.
(
sleep 3
if kill -0 "$pid" 2>/dev/null; then
# Forcefully kill child after additional 3s.
(
sleep 3 || true
if kill -0 "$pid" 2>/dev/null; then
echo "Forcefully killing $pid" >&2
kill -KILL "$pid"
fi
) &
wait_timeout_pid=$!
kill -TERM "$pid"
wait_for_pid "$pid"
else
wait_timeout_pid=
fi
) &
wait_timeout_pid=$!
wait "$wait_timeout_pid"
}
sigint() {
ret=$?
if [[ "$got_sigint" == 1 ]]; then
exit "$ret"
fi
got_sigint=1
}
cleanup() {
if [[ -n "$child_pid" ]]; then
kill_child "$child_pid"
elif [ -n "$wrapper_pid" ] && kill -0 "$wrapper_pid" 2>/dev/null; then
echo "Killing previous run (PID $wrapper_pid)"
kill "$wrapper_pid"
wait "$wrapper_pid"
fi
rm "$child_pid_pipe"
# rm "$child_ret_pipe"
}
trap 'sigint' INT
trap 'cleanup' EXIT
got_sigint=0
while true; do
child_pid=
title "… $*"
# Run command in subshell.
(
set +e
inner_ret=
inner_cleanup() {
if [[ -z "$inner_ret" ]]; then
kill_child "$child_pid"
fi
# Handle pdb.set_trace being killed.
# Ref: https://github.com/antocuni/pdb/issues/28#issuecomment-456385762
# At least for inner_ret=143 (SIGTERM).
reset -I
}
trap 'inner_cleanup' EXIT
echo "=== running: $*"
"${cmd[@]}" &
child_pid=$!
echo "$child_pid" > "$child_pid_pipe"
# echo "waiting for child pid: $child_pid"
wait $child_pid
inner_ret=$?
echo "child:exit:$inner_ret"
# if [[ "$inner_ret" != 143 ]]; then # SIGTERM
if [ "$inner_ret" = 0 ]; then
title "✔ $*"
else
title "✘ $* (ret:$inner_ret)"
fi
# fi
) </dev/tty &
wrapper_pid=$!
# Wait for child to have started.
child_pid=$(< "$child_pid_pipe")
# shellcheck disable=SC2086
inotify_cmd=(inotifywait -e close_write \
--exclude '/(__pycache__/|\.)|.*@neomake_.*' \
--format '%w%f' "${inotifywait_args[*]}") #| grep 'Watches established.'
echo "=== running: inotify_cmd: ${inotify_cmd[*]}" >&2
# shellcheck disable=SC2086
${inotify_cmd[*]}
if kill -0 "$child_pid" 2>/dev/null; then
echo "=== killing/restarting child ($child_pid)"
kill_child "$child_pid"
fi
got_sigint=0
done