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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ and versions are tracked in the repo-root `VERSION` file.
including canonical-name, alias, option-name, and option-token conflicts.
- Rejected application declaration attributes outside each public API's
documented context instead of silently accepting and discarding them.
- Isolated application run status per model while retaining the process-global
last-status value as a compatibility view of the most recently active model.
- Prevented list, CLI, and application call paths from creating or overwriting
caller-visible variables through undeclared internal scratch assignments.
- Eliminated an intermittent macOS Bash process-group race in supervised
Expand Down
5 changes: 5 additions & 0 deletions lib/bash/app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ dispatched at most once per `base_app_run`, and the application status is
preserved even if a hook fails. `INT`, `TERM`, and `HUP` map to statuses
130, 143, and 129 respectively.

`base_app_status MODEL RESULT_VARIABLE` returns that model's most recent run or
signal-derived status. A newly initialized model that has not run reports `0`.
`BASE_BASH_LIBS_APP_LAST_STATUS` remains the compatibility view of the most
recently active model, but model-aware callers should use `base_app_status`.

The policy module owns no global trap or shell-code strings itself. It uses
the stdlib's shared cleanup dispatcher and can therefore coexist with other
cleanup paths and hooks.
Expand Down
12 changes: 8 additions & 4 deletions lib/bash/app/lib_app.sh
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ __base_bash_libs_app_cleanup_dispatch__() {
*) __base_bash_libs_app_hook_dispatch__ "$model" fatal "$status" ;;
esac
__base_bash_libs_app_hook_dispatch__ "$model" cleanup "$status"
__base_bash_libs_app_models["$model|last-status"]="$status"
BASE_BASH_LIBS_APP_LAST_STATUS="$status"
return "$status"
}
Expand Down Expand Up @@ -310,6 +311,7 @@ base_app_init() {
__base_bash_libs_app_models["$model|name"]="${__base_bash_libs_app_attrs[name]-$model}"
__base_bash_libs_app_models["$model|description"]="${__base_bash_libs_app_attrs[description]-}"
__base_bash_libs_app_models["$model|config-keys"]=""
__base_bash_libs_app_models["$model|last-status"]=0
for key in normal fatal int term hup cleanup; do
__base_bash_libs_app_models["$model|hooks|$key"]=""
done
Expand Down Expand Up @@ -720,19 +722,21 @@ base_app_run() {
__base_bash_libs_app_cleanup_dispatch__ "$status"
base_std_unregister_cleanup_hook __base_bash_libs_app_cleanup_dispatch__ || true
BASE_BASH_LIBS_APP_ACTIVE_MODEL=""
__base_bash_libs_app_models["$model|last-status"]="$status"
# shellcheck disable=SC2034 # Published compatibility status for callers.
BASE_BASH_LIBS_APP_LAST_STATUS="$status"
return "$status"
}

# base_app_status - Copies the last application status.
# base_app_status - Copies the model's last run status; never-run models are 0.
base_app_status() {
local result_name="${2-}"
local model="${1-}" result_name="${2-}"
(($# == 2)) || {
__base_bash_libs_app_error__ 'base_app_status: usage: base_app_status MODEL RESULT_VARIABLE'
return 2
}
__base_bash_libs_std_assert_public_variable_names__ base_app_status "$result_name" || return 1
__base_bash_libs_std_assert_writable_output__ base_app_status "$result_name" || return 1
__base_bash_libs_app_model_exists__ "$1" || return 1
printf -v "$result_name" '%s' "$BASE_BASH_LIBS_APP_LAST_STATUS"
__base_bash_libs_app_model_exists__ "$model" || return 1
printf -v "$result_name" '%s' "${__base_bash_libs_app_models["$model|last-status"]-0}"
}
46 changes: 46 additions & 0 deletions lib/bash/app/tests/lib_app.bats
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,52 @@ assert_demo_snapshot() {
[ "$status" -eq 7 ]
}

@test "application status is isolated across normal failure signal and never-run models" {
succeeds() { return 0; }
fails() { return 7; }
local alpha_status beta_status signal_status never_status

base_app_init alpha
base_app_init beta
base_app_init signaled
base_app_init never

base_app_status never never_status
[ "$never_status" -eq 0 ]

base_app_run alpha succeeds
base_app_status alpha alpha_status
base_app_status beta beta_status
[ "$alpha_status" -eq 0 ]
[ "$beta_status" -eq 0 ]

if base_app_run beta fails; then
false
else
[ "$?" -eq 7 ]
fi
base_app_status alpha alpha_status
base_app_status beta beta_status
[ "$alpha_status" -eq 0 ]
[ "$beta_status" -eq 7 ]
[ "$BASE_BASH_LIBS_APP_LAST_STATUS" -eq 7 ]

BASE_BASH_LIBS_APP_ACTIVE_MODEL=signaled
if __base_bash_libs_app_cleanup_dispatch__ 143; then
false
else
[ "$?" -eq 143 ]
fi
BASE_BASH_LIBS_APP_ACTIVE_MODEL=""
base_app_status signaled signal_status
base_app_status beta beta_status
base_app_status never never_status
[ "$signal_status" -eq 143 ]
[ "$beta_status" -eq 7 ]
[ "$never_status" -eq 0 ]
[ "$BASE_BASH_LIBS_APP_LAST_STATUS" -eq 143 ]
}

@test "source is idempotent" {
source "$BASE_BASH_DIR/app/lib_app.sh"
[ "$(type -t base_app_run)" = function ]
Expand Down
Loading