testsAndMisc/linux_configuration/scripts/meta/shell_check.sh
Krzysztof kuhy Rudnicki a84556ac2a Split shell_check.sh into an entry script and three libs
428 lines -> 121, with lib/shell_check_lint.sh (171),
lib/shell_check_install.sh (86) and lib/shell_check_discover.sh (78).

The temp-file paths (TMPDIR, ABS_FILES_Z, REL_FILES_Z) are set once in
the entry before any lib is sourced and only read afterwards, so nothing
mutable crosses a seam. shellcheck was clean on the first attempt.

Runtime check is --skip-install --list-only --verbose, diffed against the
same run from a detached worktree at HEAD: 318 files before, 321 now,
the delta being exactly the three new libs the discovery walk now sees.
Nothing removed.

Not verified: the linting path itself. --skip-install does not gate the
AUR branch of install_linters, so a full run cannot be done under
decision 6 -- I learned that by running it, which installed four AUR
build deps before I killed it. The user chose to leave them. run_linters
moved as one intact block with no interior edit and the line-set diff
shows zero lines lost, so the seam risk is confined to its two braces.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
2026-08-16 21:57:19 +02:00

122 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# A one-stop shell linting helper for this repo.
# - Installs shell linters on Arch Linux (shellcheck, shfmt) and optionally via AUR if available
# - Discovers shell scripts in the repository (by extension or shebang)
# - Runs: shellcheck, shfmt (diff mode), optional: checkbashisms, bashate, and shell syntax checks (bash -n, zsh -n, sh/dash -n)
# - Prints a summarized report and returns non-zero if any linter reports issues
#
# Usage:
# scripts/meta/shell_check.sh [--path DIR] [--skip-install] [--install-only] [--list-only] [--verbose]
#
# Notes:
# - Arch install uses pacman: shellcheck shfmt
# - Optional linters if available (installed already or via AUR helper yay/paru): checkbashisms, bashate
# - On non-Arch systems, install is skipped with a helpful hint
set -uo pipefail
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
# Source common library for log_info, log_warn, log_error
# shellcheck source=../lib/common.sh
source "$SCRIPT_DIR/../lib/common.sh"
DEFAULT_ROOT=$(cd -- "$SCRIPT_DIR/../../" && pwd)
ROOT_DIR="$DEFAULT_ROOT"
SKIP_INSTALL="false"
INSTALL_ONLY="false"
LIST_ONLY="false"
VERBOSE="false"
usage() {
cat << EOF
Usage: $(basename "$0") [options]
Options:
--path DIR Root directory to scan (default: repo root at $DEFAULT_ROOT)
--skip-install Skip installing linters
--install-only Only install linters, do not scan
--list-only Only list discovered shell files, do not run linters
--verbose Print additional details while running
-h, --help Show this help
Linters used:
Required: shellcheck, shfmt
Optional (if available): checkbashisms, bashate
Syntax checks: bash -n, zsh -n (if installed), sh/dash -n
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--path)
ROOT_DIR="$2"
shift 2
;;
--skip-install)
SKIP_INSTALL="true"
shift
;;
--install-only)
INSTALL_ONLY="true"
shift
;;
--list-only)
LIST_ONLY="true"
shift
;;
--verbose)
VERBOSE="true"
shift
;;
-h | --help)
usage
exit 0
;;
*)
log_error "Unknown argument: $1"
usage
exit 2
;;
esac
done
if [[ ! -d $ROOT_DIR ]]; then
log_error "Path not found: $ROOT_DIR"
exit 2
fi
TMPDIR=$(mktemp -d)
trap 'rm -rf "${TMPDIR:-}"' EXIT
ABS_FILES_Z="$TMPDIR/files_abs.zlist"
REL_FILES_Z="$TMPDIR/files_rel.zlist"
# Sourced after the options and the temp-file paths above, which they read.
source "$SCRIPT_DIR/lib/shell_check_install.sh"
source "$SCRIPT_DIR/lib/shell_check_discover.sh"
source "$SCRIPT_DIR/lib/shell_check_lint.sh"
# Main
if [[ $INSTALL_ONLY == "true" ]]; then
install_linters
exit $?
fi
# Only attempt installs if not list-only
if [[ $LIST_ONLY != "true" ]]; then
install_linters || true
fi
discover_shell_files "$ROOT_DIR"
print_file_list
if [[ $LIST_ONLY == "true" ]]; then
exit 0
fi
run_linters
exit $?