blob: f12939792b3407b27d68413e73a2947e75eaece1 (
plain)
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
|
#!/bin/bash
# Обработка аргументов командной строки
CLEARMODE=false
EXCLUDE=()
while [[ $# -gt 0 ]]; do
case "$1" in
-c|--clear)
CLEARMODE=true
shift
;;
-e|--exclude)
shift
# Разделяем переданную строку исключений по запятым или пробелам
IFS=', ' read -ra EXCLUDE <<< "$1"
shift
;;
*)
break
;;
esac
done
# Попытка загрузить конфигурационный файл
if [ -f "lstart.conf" ]; then
source lstart.conf
# Если clearmode указан в конфиге, он переопределяет командную строку
if [ "$conf_clearmode" = "true" ]; then
CLEARMODE=true
fi
fi
# Если аргументов недостаточно, используем значения из конфига
if [ $# -lt 2 ]; then
if [ -z "$conf_listen" ] || [ -z "$conf_command" ]; then
echo "Usage: $0 [options] <directory> <command> [args...]"
echo "Options:"
echo " -c, --clear Clear screen before each run"
echo " -e, --exclude ITEMS Exclude files/directories (comma or space separated)"
echo ""
echo "Or create lstart.conf with variables:"
echo " conf_listen=\"directory\""
echo " conf_command=\"command to run\""
echo " conf_exclude=(array of excluded items)"
echo " conf_clearmode=true/false"
echo
echo
echo "Example:"
echo "$0 -c -e \"main,bin\" . \"gcc -o main main.c; ./main\""
exit 1
else
listen="$conf_listen"
command="$conf_command"
# Объединяем исключения из конфига и командной строки
if [ ${#conf_exclude[@]} -gt 0 ]; then
EXCLUDE=("${conf_exclude[@]}" "${EXCLUDE[@]}")
fi
fi
else
listen="$1"
shift
command="$@"
fi
PID=""
CURRENT_HASH=""
# Функция для вычисления хеша директории с исключениями
calculate_hash () {
local exclude_pattern=""
if [ ${#EXCLUDE[@]} -gt 0 ]; then
for item in "${EXCLUDE[@]}"; do
exclude_pattern="$exclude_pattern -not -path \"*/$item\" -not -name \"$item\""
done
eval "find \"$listen\" -type f $exclude_pattern -exec md5sum {} + 2>/dev/null" | awk '{print $1}' | sort | md5sum | awk '{print $1}'
else
find "$listen" -type f -exec md5sum {} + 2>/dev/null | awk '{print $1}' | sort | md5sum | awk '{print $1}'
fi
}
# Функция запуска команды
run_command () {
if $CLEARMODE; then
clear
fi
stop_command
if ! $CLEARMODE; then
echo "Running: $command"
fi
eval "$command" &
PID=$!
}
# Функция остановки команды
stop_command() {
if [ -n "$PID" ]; then
if ! $CLEARMODE; then
echo "Stopping process $PID"
fi
# Получаем всю цепочку процессов
PIDS=$(pstree -p $PID 2>/dev/null | grep -o '([0-9]\+)' | grep -o '[0-9]\+')
if [ -n "$PIDS" ]; then
# Сначала мягкий SIGTERM
kill -TERM $PIDS 2>/dev/null
# Проверяем какие процессы остались
REMAINING=""
for P in $PIDS; do
if ps -p $P > /dev/null; then
REMAINING="$REMAINING $P"
fi
done
# Если остались процессы - жесткий SIGKILL
if [ -n "$REMAINING" ]; then
kill -KILL $REMAINING 2>/dev/null
wait $REMAINING 2>/dev/null
fi
fi
PID=""
fi
}
# Обработка сигналов для корректного завершения
trap 'stop_command; exit' SIGINT SIGTERM
# Первый запуск
CURRENT_HASH=$(calculate_hash)
run_command
# Основной цикл
while true; do
sleep 1
NEW_HASH=$(calculate_hash)
if [ "$NEW_HASH" != "$CURRENT_HASH" ]; then
if ! $CLEARMODE; then
echo "Detected changes in $listen"
fi
CURRENT_HASH="$NEW_HASH"
run_command
fi
done
|