Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/verify-split-files.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ on:
- "tests/nodejs-key-refresh.sh"
- "tests/forge-connection.sh"
- "tests/failed-command-output.sh"
- "tests/stale-silent-record.sh"
- "tests/exit-code-hints.sh"
- "tests/forge-release-json.sh"
- "tests/install-cleanup.sh"
Expand Down Expand Up @@ -64,6 +65,7 @@ on:
- "tests/nodejs-key-refresh.sh"
- "tests/forge-connection.sh"
- "tests/failed-command-output.sh"
- "tests/stale-silent-record.sh"
- "tests/exit-code-hints.sh"
- "tests/forge-release-json.sh"
- "tests/install-cleanup.sh"
Expand Down Expand Up @@ -124,6 +126,8 @@ jobs:

- name: Failed command output tests
run: bash tests/failed-command-output.sh
- name: Stale silent record tests
run: bash tests/stale-silent-record.sh

- name: Exit code hint tests
run: bash tests/exit-code-hints.sh
Expand Down
16 changes: 12 additions & 4 deletions core/error_handler.func
Original file line number Diff line number Diff line change
Expand Up @@ -665,12 +665,20 @@ error_handler() {
command="${command//\$STD/}"

# silent() knows the real failing command; the trap only sees the wrapper.
# Its record outlives a failure the caller handled, so it only counts for
# the line it came from; otherwise its capture would be sent for this one.
local from_silent=0
if [[ -n "${_SILENT_FAILED_RC:-}" ]]; then
exit_code="$_SILENT_FAILED_RC"
command="$_SILENT_FAILED_CMD"
line_number="$_SILENT_FAILED_LINE"
from_silent=1
if [[ "${_SILENT_FAILED_LINE:-}" == "$line_number" ]]; then
exit_code="$_SILENT_FAILED_RC"
command="$_SILENT_FAILED_CMD"
from_silent=1
else
if [[ -n "${_SILENT_FAILED_LOG:-}" ]]; then
rm -f "${_SILENT_FAILED_LOG}.errinfo" 2>/dev/null
fi
unset _SILENT_FAILED_LOG
fi
unset _SILENT_FAILED_RC _SILENT_FAILED_CMD _SILENT_FAILED_LINE
fi

Expand Down
5 changes: 3 additions & 2 deletions tests/failed-command-output.sh
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,9 @@ msg_error() { echo "error: $*"; }
handler_output() {
# error_handler exits, so it runs in a subshell with the state silent() leaves behind.
(
export _SILENT_FAILED_RC=1 _SILENT_FAILED_CMD="pnpm install" _SILENT_FAILED_LINE=34 _SILENT_FAILED_LOG="$LOGFILE"
error_handler 1 "silent pnpm install" 2>&1
export _SILENT_FAILED_RC=1 _SILENT_FAILED_CMD="pnpm install" _SILENT_FAILED_LOG="$LOGFILE"
# The record only counts for the line it came from.
_SILENT_FAILED_LINE=$LINENO error_handler 1 "silent pnpm install" 2>&1
)
}
reset
Expand Down
49 changes: 49 additions & 0 deletions tests/stale-silent-record.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# silent() leaves its record for the ERR trap. After `$STD cmd || true` the
# record and its .errinfo stayed until the next $STD call, so a later plain
# command's failure was reported as the handled one.
set -uo pipefail

CORE_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
eval "$(awk '/^error_handler[(][)] [{]/,/^}/' "$CORE_DIR/core/error_handler.func")"

TEST_DIR="$(mktemp -d)"
trap 'rm -rf -- "$TEST_DIR"' EXIT
LOG="$TEST_DIR/install.log"
ERRINFO="$LOG.errinfo"
passed=0 failed=0

_eh_explanation() { echo "explained"; }
_eh_report() {
printf 'REPORT %s|%s|%s\n' "$1" "$2" "$3"
exit 0
}

expect() {
if [[ "$2" == "$3" ]]; then
echo "PASS $1"
passed=$((passed + 1))
else
echo "FAIL $1: expected <$2>, got <$3>" >&2
failed=$((failed + 1))
fi
}
handled_failure() {
echo "E: Unable to locate package intel-basekit" >"$LOG"
printf '%s\n' 'EXIT_CODE=100' 'LINE=5' 'COMMAND=apt install -y intel-basekit' '--- OUTPUT ---' 'E: Unable to locate package intel-basekit' >"$ERRINFO"
export _SILENT_FAILED_RC=100 _SILENT_FAILED_CMD='apt install -y intel-basekit' _SILENT_FAILED_LINE="$1" _SILENT_FAILED_LOG="$LOG"
}

# A later failure on another line is its own.
handled_failure 5
out="$(error_handler 1 'systemctl enable -q --now open-webui')"
expect "the later failure keeps its code and command" 1 "$(grep -c 'REPORT 1|systemctl enable -q --now open-webui|' <<<"$out")"
expect "the handled failure's capture is dropped" 0 "$(ls "$ERRINFO" 2>/dev/null | wc -l)"

# On its own line the record is what the trap reports.
line=$LINENO; handled_failure "$line"; out="$(error_handler 1 'silent apt install -y intel-basekit')"
expect "silent's record is used for its own line" 1 "$(grep -c 'REPORT 100|apt install -y intel-basekit|' <<<"$out")"
expect "its capture is kept" 1 "$(ls "$ERRINFO" 2>/dev/null | wc -l)"

echo "$passed passed, $failed failed"
((failed == 0))
Loading