Skip to content

Commit 4f32d45

Browse files
authored
doc: Sourcing this is bad.
Refactor script to improve safety and readability.
1 parent f1878ae commit 4f32d45

File tree

1 file changed

+39
-27
lines changed

1 file changed

+39
-27
lines changed

fix-indent.sh

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env bash
2+
set -u
23

34
usage() {
45
cat <<'EOF'
@@ -23,23 +24,27 @@ Rules enforced:
2324
EOF
2425
}
2526

27+
# If sourced, "exit" would kill the caller shell. Use safe_exit.
28+
safe_exit() {
29+
local code="${1:-0}"
30+
if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then
31+
return "$code"
32+
fi
33+
exit "$code"
34+
}
35+
2636
process_file() {
2737
local file="$1"
28-
local tmp
38+
local tmp dir
2939

30-
# Only operate on regular files
3140
[[ -f "$file" ]] || return 0
3241

33-
tmp="$(mktemp -- "${file}.fix_indent.XXXXXX")" || {
42+
dir="$(dirname -- "$file")"
43+
tmp="$(mktemp --tmpdir="$dir" ".fix_indent.XXXXXX")" || {
3444
echo "fix_indent: mktemp failed for: $file" >&2
3545
return 1
3646
}
3747

38-
# AWK filter:
39-
# - Convert tabs to 4 spaces
40-
# - Collapse blank runs to a single indented blank line (indent from next non-blank line)
41-
# - Drop trailing blanks at EOF
42-
# - Preserve CRLF if present
4348
awk '
4449
BEGIN { pending_blank = 0; use_crlf = 0 }
4550
@@ -52,15 +57,16 @@ process_file() {
5257
s = $0
5358
if (sub(/\r$/, "", s)) use_crlf = 1
5459
60+
# Tabs are forbidden: replace with 4 spaces (everywhere)
5561
gsub(/\t/, " ", s)
5662
57-
# whitespace-only line => treat as blank
63+
# whitespace-only line => treat as blank (after tab expansion this is spaces-only)
5864
if (s ~ /^[ ]*$/) {
5965
pending_blank = 1
6066
next
6167
}
6268
63-
# if we have pending blanks, emit exactly one blank indented to this line
69+
# If we have pending blanks, emit exactly one blank indented to this line
6470
if (pending_blank) {
6571
match(s, /^[ ]*/)
6672
emit(substr(s, RSTART, RLENGTH))
@@ -71,7 +77,7 @@ process_file() {
7177
}
7278
7379
END {
74-
# If file ends with blanks, emit nothing (no blank lines at/beyond EOF)
80+
# Trailing blanks at EOF are dropped (no output here)
7581
}
7682
' "$file" > "$tmp"
7783

@@ -81,20 +87,22 @@ process_file() {
8187
return 1
8288
fi
8389

84-
# Avoid touching files that would be unchanged
8590
if cmp -s -- "$file" "$tmp"; then
8691
rm -f -- "$tmp"
8792
return 0
8893
fi
8994

90-
# Overwrite in place (preserves mode/owner; updates mtime)
91-
if ! cat -- "$tmp" > "$file"; then
92-
echo "fix_indent: write failed for: $file" >&2
95+
# Preserve permissions where possible
96+
chmod --reference="$file" "$tmp" 2>/dev/null || true
97+
chown --reference="$file" "$tmp" 2>/dev/null || true
98+
99+
# Atomic replace
100+
if ! mv -f -- "$tmp" "$file"; then
101+
echo "fix_indent: replace failed for: $file" >&2
93102
rm -f -- "$tmp"
94103
return 1
95104
fi
96105

97-
rm -f -- "$tmp"
98106
return 0
99107
}
100108

@@ -104,13 +112,13 @@ main() {
104112

105113
if [[ $# -eq 0 ]]; then
106114
usage >&2
107-
exit 2
115+
safe_exit 2
108116
fi
109117

110118
case "$1" in
111119
-h)
112120
usage
113-
exit 0
121+
safe_exit 0
114122
;;
115123
-R)
116124
recursive=1
@@ -123,40 +131,44 @@ main() {
123131
fi
124132
if [[ $# -ne 0 ]]; then
125133
usage >&2
126-
exit 2
134+
safe_exit 2
127135
fi
128136
;;
129137
-*)
130138
usage >&2
131-
exit 2
139+
safe_exit 2
132140
;;
133141
*)
134142
if [[ $# -ne 1 ]]; then
135143
usage >&2
136-
exit 2
144+
safe_exit 2
137145
fi
138146
target="$1"
139147
;;
140148
esac
141149

142150
if [[ $recursive -eq 0 ]]; then
143-
# Single file mode
144-
process_file "$target" || exit $?
145-
exit 0
151+
process_file "$target" || safe_exit $?
152+
safe_exit 0
146153
fi
147154

148-
# Recursive mode
149155
if [[ ! -e "$target" ]]; then
150156
echo "fix_indent: path not found: $target" >&2
151-
exit 1
157+
safe_exit 1
152158
fi
153159

154160
local rc=0
155161
while IFS= read -r -d '' f; do
156162
process_file "$f" || rc=1
157163
done < <(find "$target" -type f -name '*.py' -print0)
158164

159-
exit $rc
165+
safe_exit "$rc"
160166
}
161167

168+
# If someone sources it, don't run it implicitly; tell them what to do.
169+
if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then
170+
echo "fix_indent: don’t source this script. Run it: ./fix_indent [args]" >&2
171+
return 2
172+
fi
173+
162174
main "$@"

0 commit comments

Comments
 (0)