fix(kitty): read file permissions correctly where stat is GNU
`chezmoi apply` on Linux printed "could not regenerate kitty theme files" every run. GNU stat reads -f as --file-system, so `stat -f '%Lp' file` prints a block of filesystem info to stdout and exits non-zero. The `|| stat -c '%a'` fallback then appended the real answer to that block, and chmod rejected the result, failing the script under set -e. Replace the chain with a file_mode() helper in both scripts: try the GNU form first, since BSD rejects -c cleanly without printing anything, and accept the answer only if it is octal. Covered by a new case in tests/test_theme_mode.sh using a stat stub that reproduces GNU's behaviour; it fails against the old chain.
This commit is contained in:
parent
5b58460618
commit
a84778a640
@ -14,6 +14,22 @@
|
|||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
# Permission bits of a file, or 600 if they cannot be read. GNU stat spells this
|
||||||
|
# `-c %a` while BSD/macOS spells it `-f %Lp`, and each mis-parses the other's
|
||||||
|
# form -- GNU treats `-f` as --file-system and prints a block of filesystem info
|
||||||
|
# before failing -- so try one at a time and only accept an octal answer.
|
||||||
|
file_mode() {
|
||||||
|
_m=$(stat -c '%a' "$1" 2>/dev/null) || _m=''
|
||||||
|
case "$_m" in
|
||||||
|
[0-7][0-7][0-7] | [0-7][0-7][0-7][0-7]) printf '%s\n' "$_m"; return 0 ;;
|
||||||
|
esac
|
||||||
|
_m=$(stat -f '%Lp' "$1" 2>/dev/null) || _m=''
|
||||||
|
case "$_m" in
|
||||||
|
[0-7][0-7][0-7] | [0-7][0-7][0-7][0-7]) printf '%s\n' "$_m"; return 0 ;;
|
||||||
|
esac
|
||||||
|
printf '600\n'
|
||||||
|
}
|
||||||
|
|
||||||
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||||
config_dir=${1:-"$script_dir"}
|
config_dir=${1:-"$script_dir"}
|
||||||
canonical_dir="$config_dir/themes"
|
canonical_dir="$config_dir/themes"
|
||||||
@ -54,12 +70,9 @@ for appearance in dark light no-preference; do
|
|||||||
[ -f "$canonical" ] || continue
|
[ -f "$canonical" ] || continue
|
||||||
|
|
||||||
generated="$config_dir/$appearance-theme.auto.conf"
|
generated="$config_dir/$appearance-theme.auto.conf"
|
||||||
# stat -f is BSD/macOS, stat -c is GNU; this also runs on Linux boxes.
|
|
||||||
mode_bits=600
|
mode_bits=600
|
||||||
if [ -f "$generated" ]; then
|
if [ -f "$generated" ]; then
|
||||||
mode_bits=$(stat -f '%Lp' "$generated" 2>/dev/null \
|
mode_bits=$(file_mode "$generated")
|
||||||
|| stat -c '%a' "$generated" 2>/dev/null \
|
|
||||||
|| echo 600)
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tmp=$(mktemp "$generated.tmp.XXXXXX")
|
tmp=$(mktemp "$generated.tmp.XXXXXX")
|
||||||
|
|||||||
@ -2,6 +2,22 @@
|
|||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
# Permission bits of a file, or 600 if they cannot be read. GNU stat spells this
|
||||||
|
# `-c %a` while BSD/macOS spells it `-f %Lp`, and each mis-parses the other's
|
||||||
|
# form -- GNU treats `-f` as --file-system and prints a block of filesystem info
|
||||||
|
# before failing -- so try one at a time and only accept an octal answer.
|
||||||
|
file_mode() {
|
||||||
|
_m=$(stat -c '%a' "$1" 2>/dev/null) || _m=''
|
||||||
|
case "$_m" in
|
||||||
|
[0-7][0-7][0-7] | [0-7][0-7][0-7][0-7]) printf '%s\n' "$_m"; return 0 ;;
|
||||||
|
esac
|
||||||
|
_m=$(stat -f '%Lp' "$1" 2>/dev/null) || _m=''
|
||||||
|
case "$_m" in
|
||||||
|
[0-7][0-7][0-7] | [0-7][0-7][0-7][0-7]) printf '%s\n' "$_m"; return 0 ;;
|
||||||
|
esac
|
||||||
|
printf '600\n'
|
||||||
|
}
|
||||||
|
|
||||||
config_dir=${1:-"$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"}
|
config_dir=${1:-"$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"}
|
||||||
|
|
||||||
for appearance in dark light no-preference; do
|
for appearance in dark light no-preference; do
|
||||||
@ -22,10 +38,7 @@ for appearance in dark light no-preference; do
|
|||||||
trap 'rm -f "$tmp"' EXIT HUP INT TERM
|
trap 'rm -f "$tmp"' EXIT HUP INT TERM
|
||||||
awk '$1 != "macos_titlebar_color"' "$config_file" > "$tmp"
|
awk '$1 != "macos_titlebar_color"' "$config_file" > "$tmp"
|
||||||
printf '\nmacos_titlebar_color background\n' >> "$tmp"
|
printf '\nmacos_titlebar_color background\n' >> "$tmp"
|
||||||
# stat -f is BSD/macOS, stat -c is GNU; this also runs on Linux boxes.
|
chmod "$(file_mode "$config_file")" "$tmp"
|
||||||
chmod "$(stat -f '%Lp' "$config_file" 2>/dev/null \
|
|
||||||
|| stat -c '%a' "$config_file" 2>/dev/null \
|
|
||||||
|| echo 600)" "$tmp"
|
|
||||||
mv -f "$tmp" "$config_file"
|
mv -f "$tmp" "$config_file"
|
||||||
trap - EXIT HUP INT TERM
|
trap - EXIT HUP INT TERM
|
||||||
done
|
done
|
||||||
|
|||||||
@ -149,4 +149,36 @@ run_fish dark 'theme >/dev/null'
|
|||||||
|
|
||||||
"$root/tests/verify_auto_themes.sh" "$config_dir"
|
"$root/tests/verify_auto_themes.sh" "$config_dir"
|
||||||
|
|
||||||
|
# --- the scripts must work where stat is GNU, not BSD ---------------------
|
||||||
|
# GNU stat reads -f as --file-system, so `stat -f '%Lp' file` prints a block of
|
||||||
|
# filesystem info to stdout *and* exits non-zero. Chaining it into `|| stat -c`
|
||||||
|
# concatenates that block with the real answer and chmod then rejects it, which
|
||||||
|
# broke `chezmoi apply` on Linux with "could not regenerate kitty theme files".
|
||||||
|
cat >"$fake_bin/stat" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
case "$1" in
|
||||||
|
-c) shift; [ "$1" = "%a" ] && shift; /usr/bin/stat -f '%Lp' "$1" ;;
|
||||||
|
-f) shift
|
||||||
|
echo " File: \"$2\""
|
||||||
|
echo "Block size: 4096 Fundamental block size: 4096"
|
||||||
|
exit 1 ;;
|
||||||
|
*) exec /usr/bin/stat "$@" ;;
|
||||||
|
esac
|
||||||
|
EOF
|
||||||
|
chmod +x "$fake_bin/stat"
|
||||||
|
|
||||||
|
echo auto >"$config_dir/theme-mode"
|
||||||
|
if ! PATH="$fake_bin:/usr/bin:/bin" "$root/apply-theme-mode.sh" "$config_dir" \
|
||||||
|
>/dev/null 2>&1; then
|
||||||
|
echo "not ok - apply-theme-mode.sh fails where stat is GNU" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
for appearance in dark light no-preference; do
|
||||||
|
[ -f "$config_dir/$appearance-theme.auto.conf" ] || {
|
||||||
|
echo "not ok - GNU stat run did not produce $appearance theme" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
rm -f "$fake_bin/stat"
|
||||||
|
|
||||||
echo "PASS: theme mode is remembered, survives kitten themes, and collapses to auto"
|
echo "PASS: theme mode is remembered, survives kitten themes, and collapses to auto"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user