diff --git a/deploy.sh b/deploy.sh index f34aee8..9922330 100755 --- a/deploy.sh +++ b/deploy.sh @@ -56,9 +56,12 @@ # Exit Codes: # - 0: The deployment finished. # - 1: A step failed. +# - 126: A required command is not executable. # - 127: A required command is missing. # # Version History: +# v1.1 2026-09-13 +# Normalize shared usage and command checks across shell scripts. # v1.0 2026-08-14 # Initial release. # @@ -72,8 +75,9 @@ DATA_GROUP=${DATA_GROUP:-www-data} VENV_DIR="$TARGET_DIR/.venv" SOURCE_DIR=$(cd "$(dirname "$0")" && pwd) -# Display this script's header as usage information +# Display full script header information extracted from the top comment block usage() { + check_commands awk awk ' BEGIN { in_header = 0 } /^#+$/ && length($0) >= 10 { if (!in_header) { in_header = 1; next } else exit } @@ -82,12 +86,16 @@ usage() { exit 0 } -# Check that the required commands are available +# Check if required commands are available and executable check_commands() { - for cmd in "$PYTHON" sudo install; do - if ! command -v "$cmd" >/dev/null 2>&1; then - echo "[ERROR] Command not found: $cmd" >&2 + for cmd in "$@"; do + cmd_path=$(command -v "$cmd" 2>/dev/null) + if [ -z "$cmd_path" ]; then + echo "[ERROR] Command '$cmd' is not installed. Please install $cmd and try again." >&2 exit 127 + elif [ ! -x "$cmd_path" ]; then + echo "[ERROR] Command '$cmd' is not executable. Please check the permissions." >&2 + exit 126 fi done } @@ -198,7 +206,7 @@ main() { case "${1:-}" in -h|--help) usage ;; esac - check_commands + check_commands "$PYTHON" sudo install check_python create_directories create_environment_file diff --git a/doc/POLICY.md b/doc/POLICY.md index 15e5987..c9d0df3 100644 --- a/doc/POLICY.md +++ b/doc/POLICY.md @@ -319,6 +319,16 @@ This repository was left behind by exactly the practices this section forbids. - Define `usage()`, `main()`, and call `main "$@"` at the end. - An interpreter path is a default that can be overridden, not a constant compiled into the script. +- A helper name shared with other id774 shell scripts is an interface. The same + name means the same arguments, exit statuses, side effects and implementation. + Do not specialize a shared helper in place. +- Repository-specific behavior belongs at the call site or in a differently + named helper. If the behavior differs, the function name differs. +- `check_commands()` takes the command names to inspect in `"$@"`, resolves each + with `command -v`, exits `127` when a command is unavailable and `126` when the + resolved path is not executable. +- The shared header-extracting `usage()` calls `check_commands awk` before + invoking `awk`, prints the header block and exits `0`. ### 2.7 Documentation and Versioning diff --git a/doc/VERSIONS b/doc/VERSIONS index f763072..e9e93c5 100644 --- a/doc/VERSIONS +++ b/doc/VERSIONS @@ -14,6 +14,8 @@ v1.0.2 (Release Date: TBD) - Redact any echoed API key before a provider error reaches logs or stderr. - Reject invalid chart/summary ranges and stock-list rows missing code or name. - Replace generated CSV/TXT files atomically so failed writes keep good data. +- Normalize shell helper contracts so missing and non-executable commands + report statuses `127` and `126` consistently. v1.0.1 (2026-08-26) ------------------- diff --git a/run.sh b/run.sh index 553c137..2b8a8c8 100755 --- a/run.sh +++ b/run.sh @@ -62,8 +62,12 @@ # Exit Codes: # - 0: Every step succeeded. # - 1: At least one step failed. +# - 126: A required command is not executable. +# - 127: A required command is missing. # # Version History: +# v1.1 2026-09-13 +# Normalize shared usage and command checks; keep pipeline checks separate. # v1.0 2026-08-14 # Initial release. # @@ -102,8 +106,9 @@ NOTIFY="$VENV_DIR/bin/finance-notify" failures=0 -# Display this script's header as usage information +# Display full script header information extracted from the top comment block usage() { + check_commands awk awk ' BEGIN { in_header = 0 } /^#+$/ && length($0) >= 10 { if (!in_header) { in_header = 1; next } else exit } @@ -125,8 +130,22 @@ log() { echo "$@" >>"$JOBLOG" 2>&1 } -# Check that the commands this job drives are installed +# Check if required commands are available and executable check_commands() { + for cmd in "$@"; do + cmd_path=$(command -v "$cmd" 2>/dev/null) + if [ -z "$cmd_path" ]; then + echo "[ERROR] Command '$cmd' is not installed. Please install $cmd and try again." >&2 + exit 127 + elif [ ! -x "$cmd_path" ]; then + echo "[ERROR] Command '$cmd' is not executable. Please check the permissions." >&2 + exit 126 + fi + done +} + +# Check that the finance pipeline commands are installed +check_pipeline_commands() { for cmd in "$CHARTS" "$SUMMARY" "$NOTIFY"; do if [ ! -x "$cmd" ]; then echo "[ERROR] Command not found: $cmd" >&2 @@ -134,10 +153,6 @@ check_commands() { exit 1 fi done - if ! command -v date >/dev/null 2>&1; then - echo "[ERROR] Command not found: date" >&2 - exit 127 - fi } # Check that the fetching step has the credential it needs @@ -226,7 +241,8 @@ main() { -h|--help) usage ;; esac load_environment - check_commands + check_pipeline_commands + check_commands date check_credential check_environment