mirror of
https://github.com/tw93/Mole.git
synced 2026-03-22 18:30:08 +00:00
fix: preserve interrupt semantics and restore purge traps
This commit is contained in:
@@ -121,6 +121,8 @@ Security-sensitive cleanup paths are covered by BATS regression tests, including
|
||||
- `tests/clean_user_core.bats`
|
||||
- `tests/clean_dev_caches.bats`
|
||||
- `tests/clean_system_maintenance.bats`
|
||||
- `tests/purge.bats`
|
||||
- `tests/core_safe_functions.bats`
|
||||
|
||||
**System Memory Reports** computation uses bulk `find -exec stat` to avoid bash loop child-process limits on corrupted systems.
|
||||
`bin/clean.sh` dry-run export temp files rely on tracked temp lifecycle (`create_temp_file()` + trap cleanup) to avoid orphan temp artifacts.
|
||||
@@ -132,6 +134,7 @@ Latest local verification for this release branch:
|
||||
- `bats tests/clean_user_core.bats` passed (13/13)
|
||||
- `bats tests/clean_dev_caches.bats` passed (8/8)
|
||||
- `bats tests/clean_system_maintenance.bats` passed (40/40)
|
||||
- `bats tests/purge.bats tests/core_safe_functions.bats` passed (67/67)
|
||||
|
||||
Run tests:
|
||||
|
||||
|
||||
@@ -569,16 +569,38 @@ select_purge_categories() {
|
||||
fi
|
||||
done
|
||||
local original_stty=""
|
||||
local previous_exit_trap=""
|
||||
local previous_int_trap=""
|
||||
local previous_term_trap=""
|
||||
local terminal_restored=false
|
||||
if [[ -t 0 ]] && command -v stty > /dev/null 2>&1; then
|
||||
original_stty=$(stty -g 2> /dev/null || echo "")
|
||||
fi
|
||||
previous_exit_trap=$(trap -p EXIT || true)
|
||||
previous_int_trap=$(trap -p INT || true)
|
||||
previous_term_trap=$(trap -p TERM || true)
|
||||
# Terminal control functions
|
||||
restore_terminal() {
|
||||
# Avoid trap churn when restore is called repeatedly via RETURN/EXIT paths.
|
||||
if [[ "${terminal_restored:-false}" == "true" ]]; then
|
||||
return
|
||||
fi
|
||||
terminal_restored=true
|
||||
|
||||
trap - EXIT INT TERM
|
||||
show_cursor
|
||||
if [[ -n "${original_stty:-}" ]]; then
|
||||
stty "${original_stty}" 2> /dev/null || stty sane 2> /dev/null || true
|
||||
fi
|
||||
if [[ -n "$previous_exit_trap" ]]; then
|
||||
eval "$previous_exit_trap"
|
||||
fi
|
||||
if [[ -n "$previous_int_trap" ]]; then
|
||||
eval "$previous_int_trap"
|
||||
fi
|
||||
if [[ -n "$previous_term_trap" ]]; then
|
||||
eval "$previous_term_trap"
|
||||
fi
|
||||
}
|
||||
# shellcheck disable=SC2329
|
||||
handle_interrupt() {
|
||||
|
||||
@@ -249,6 +249,11 @@ safe_remove() {
|
||||
local rm_exit=0
|
||||
error_msg=$(rm -rf "$path" 2>&1) || rm_exit=$? # safe_remove
|
||||
|
||||
# Preserve interrupt semantics so callers can abort long-running deletions.
|
||||
if [[ $rm_exit -ge 128 ]]; then
|
||||
return "$rm_exit"
|
||||
fi
|
||||
|
||||
if [[ $rm_exit -eq 0 ]]; then
|
||||
# Log successful removal
|
||||
log_operation "${MOLE_CURRENT_COMMAND:-clean}" "REMOVED" "$path" "$size_human"
|
||||
|
||||
@@ -110,6 +110,19 @@ teardown() {
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "safe_remove preserves interrupt exit codes" {
|
||||
local test_file="$TEST_DIR/interrupt_file"
|
||||
echo "test" > "$test_file"
|
||||
|
||||
run bash -c "
|
||||
source '$PROJECT_ROOT/lib/core/common.sh'
|
||||
rm() { return 130; }
|
||||
safe_remove '$test_file' true
|
||||
"
|
||||
[ "$status" -eq 130 ]
|
||||
[ -f "$test_file" ]
|
||||
}
|
||||
|
||||
@test "safe_remove in silent mode suppresses error output" {
|
||||
run bash -c "source '$PROJECT_ROOT/lib/core/common.sh'; safe_remove '/System/test' true 2>&1"
|
||||
[ "$status" -eq 1 ]
|
||||
|
||||
@@ -308,6 +308,44 @@ EOF
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "select_purge_categories restores caller EXIT/INT/TERM traps" {
|
||||
run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc <<'EOF'
|
||||
set -euo pipefail
|
||||
source "$PROJECT_ROOT/lib/clean/project.sh"
|
||||
trap 'echo parent-exit' EXIT
|
||||
trap 'echo parent-int' INT
|
||||
trap 'echo parent-term' TERM
|
||||
|
||||
before_exit=$(trap -p EXIT)
|
||||
before_int=$(trap -p INT)
|
||||
before_term=$(trap -p TERM)
|
||||
|
||||
PURGE_CATEGORY_SIZES="1"
|
||||
PURGE_RECENT_CATEGORIES="false"
|
||||
select_purge_categories "demo" <<< $'\n' > /dev/null 2>&1 || true
|
||||
|
||||
after_exit=$(trap -p EXIT)
|
||||
after_int=$(trap -p INT)
|
||||
after_term=$(trap -p TERM)
|
||||
|
||||
if [[ "$before_exit" == "$after_exit" && "$before_int" == "$after_int" && "$before_term" == "$after_term" ]]; then
|
||||
echo "PASS"
|
||||
else
|
||||
echo "FAIL"
|
||||
echo "before_exit=$before_exit"
|
||||
echo "after_exit=$after_exit"
|
||||
echo "before_int=$before_int"
|
||||
echo "after_int=$after_int"
|
||||
echo "before_term=$before_term"
|
||||
echo "after_term=$after_term"
|
||||
exit 1
|
||||
fi
|
||||
EOF
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"PASS"* ]]
|
||||
}
|
||||
|
||||
@test "confirm_purge_cleanup accepts Enter" {
|
||||
run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc <<'EOF'
|
||||
set -euo pipefail
|
||||
|
||||
Reference in New Issue
Block a user