Fix unbound BASH_SOURCE under bash -c invocation, the actual documented run command
BASH_SOURCE has zero elements when a script arrives as `bash -c "$(curl ...)"` (no backing file at all) rather than a real path or /dev/fd process- substitution handle. Under set -u this crashed immediately on the REPO_DIR line, and the bottom sourcing guard's $BASH_SOURCE/$0 comparison would have silently never run main() either way (bash -c sets $0 to "bash", which never matches an empty BASH_SOURCE default). Guarded the REPO_DIR line with a safe default, and replaced the sourcing guard with the standard `return 0` idiom, which correctly distinguishes sourced (bats tests) from directly-executed (file, bash -c, process substitution) in every invocation style. Added a regression test that runs the actual `bash -c "$(cat install.sh)"` command end-to-end against the real public repo, not just sourced functions.
This commit is contained in:
1 parent
478450b209
commit
e6b03153df
2 files changed
+48
-2
No files matched your search
+12
-2
@@ -1,7 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# ${BASH_SOURCE[0]} is unset (not just empty) when this script arrives as a
|
||||
# `bash -c "$(curl ...)"` command string rather than a real file -- guard it
|
||||
# so `set -u` doesn't blow up. `dirname ""` -> "." (current dir), which
|
||||
# ensure_repo_files() below correctly treats as "no local checkout, fetch."
|
||||
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-}")" && pwd)"
|
||||
CONFIG_HOME="${CONFIG_HOME:-${XDG_CONFIG_HOME:-$HOME/.config}}"
|
||||
LOCAL_BIN="${LOCAL_BIN:-$HOME/.local/bin}"
|
||||
HYPREVO_RAW_BASE="${HYPREVO_RAW_BASE:-https://git.edemilov.ru/edemilov/hyprevo/raw/branch/master}"
|
||||
@@ -266,6 +270,12 @@ main() {
|
||||
echo "hyprevo: done."
|
||||
}
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
# `return` only succeeds at top level when the script is being sourced (as
|
||||
# tests/install.bats does). Direct execution -- a real file, `bash -c "..."`,
|
||||
# or `bash <(curl ...)` process substitution -- all fail `return`, so `main`
|
||||
# runs. This is more robust here than comparing $BASH_SOURCE/$0: under
|
||||
# `bash -c "$(curl ...)"` there's no backing file at all, so BASH_SOURCE is
|
||||
# empty and $0 is just "bash" -- they'd never match even with a safe default.
|
||||
if ! (return 0 2>/dev/null); then
|
||||
main "$@"
|
||||
fi
|
||||
@@ -298,3 +298,39 @@ EOF
|
||||
|
||||
rm -rf "$tmp_home" "$stub_bin"
|
||||
}
|
||||
|
||||
@test "install.sh runs end-to-end via bash -c \"\$(cat install.sh)\" (the real distribution command)" {
|
||||
# Regression test: BASH_SOURCE has zero elements under `bash -c "..."`
|
||||
# (no backing file at all), which broke both the REPO_DIR line and the
|
||||
# sourcing guard under `set -u`. Exercise the actual documented install
|
||||
# command, not just sourced functions, so this can't silently regress.
|
||||
local tmp_home
|
||||
tmp_home="$(mktemp -d)"
|
||||
local stub_bin
|
||||
stub_bin="$(mktemp -d)"
|
||||
|
||||
for cmd in pacman systemctl hyprctl sudo; do
|
||||
cat > "$stub_bin/$cmd" <<EOF
|
||||
#!/usr/bin/env bash
|
||||
echo "$cmd \$*" >> "$tmp_home/log"
|
||||
if [ "$cmd" = "sudo" ]; then exec "\$@"; fi
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$stub_bin/$cmd"
|
||||
done
|
||||
|
||||
PATH="$stub_bin:$PATH" \
|
||||
HOME="$tmp_home" \
|
||||
HYPREVO_NONINTERACTIVE=1 \
|
||||
HYPREVO_TERMINAL=Konsole \
|
||||
HYPREVO_FILEMANAGER=Dolphin \
|
||||
HYPREVO_MAIL=Thunderbird \
|
||||
HYPREVO_CLOUDSYNC=Nextcloud \
|
||||
run bash -c "$(cat "${BATS_TEST_DIRNAME}/../install.sh")"
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"hyprevo: done."* ]]
|
||||
[ -f "$tmp_home/.config/hypr/hyprland.conf" ]
|
||||
|
||||
rm -rf "$tmp_home" "$stub_bin"
|
||||
}
|
||||
Reference in new issue
Block a user