Merge pull request #12072 from XuehaiPan/refactor-shell-formatter
style: add shfmt exit status to `brew style`
This commit is contained in:
commit
e011b15953
@ -65,12 +65,16 @@ module Homebrew
|
|||||||
run_shellcheck(shell_files, output_type)
|
run_shellcheck(shell_files, output_type)
|
||||||
end
|
end
|
||||||
|
|
||||||
run_shfmt(shell_files, fix: fix) if ruby_files.none? || shell_files.any?
|
shfmt_result = if ruby_files.any? && shell_files.none?
|
||||||
|
true
|
||||||
|
else
|
||||||
|
run_shfmt(shell_files, fix: fix)
|
||||||
|
end
|
||||||
|
|
||||||
if output_type == :json
|
if output_type == :json
|
||||||
Offenses.new(rubocop_result + shellcheck_result)
|
Offenses.new(rubocop_result + shellcheck_result)
|
||||||
else
|
else
|
||||||
rubocop_result && shellcheck_result
|
rubocop_result && shellcheck_result && shfmt_result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,7 @@ do
|
|||||||
SHFMT_ARGS+=("${arg}")
|
SHFMT_ARGS+=("${arg}")
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
unset arg
|
||||||
|
|
||||||
FILES=()
|
FILES=()
|
||||||
for file in "$@"
|
for file in "$@"
|
||||||
@ -66,6 +67,7 @@ do
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
unset file
|
||||||
|
|
||||||
if [[ "${#FILES[@]}" == 0 ]]
|
if [[ "${#FILES[@]}" == 0 ]]
|
||||||
then
|
then
|
||||||
@ -76,6 +78,32 @@ fi
|
|||||||
### Custom shell script styling
|
### Custom shell script styling
|
||||||
###
|
###
|
||||||
|
|
||||||
|
# Check for specific patterns and prompt messages if detected
|
||||||
|
no_forbidden_patten() {
|
||||||
|
local file="$1"
|
||||||
|
local tempfile="$2"
|
||||||
|
local subject="$3"
|
||||||
|
local message="$4"
|
||||||
|
local regex_pos="$5"
|
||||||
|
local regex_neg="${6:-}"
|
||||||
|
local line
|
||||||
|
local num=0
|
||||||
|
local retcode=0
|
||||||
|
|
||||||
|
while IFS='' read -r line
|
||||||
|
do
|
||||||
|
num="$((num + 1))"
|
||||||
|
if [[ "${line}" =~ ${regex_pos} ]] &&
|
||||||
|
[[ -z "${regex_neg}" || ! "${line}" =~ ${regex_neg} ]]
|
||||||
|
then
|
||||||
|
onoe "${subject} detected at \"${file}\", line ${num}."
|
||||||
|
[[ -n "${message}" ]] && onoe "${message}"
|
||||||
|
retcode=1
|
||||||
|
fi
|
||||||
|
done <"${file}"
|
||||||
|
return "${retcode}"
|
||||||
|
}
|
||||||
|
|
||||||
# Check pattern:
|
# Check pattern:
|
||||||
# '^\t+'
|
# '^\t+'
|
||||||
#
|
#
|
||||||
@ -84,22 +112,12 @@ fi
|
|||||||
no_tabs() {
|
no_tabs() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local tempfile="$2"
|
local tempfile="$2"
|
||||||
local line
|
|
||||||
local num=0
|
|
||||||
local retcode=0
|
|
||||||
local regex_pos='^[[:space:]]+'
|
|
||||||
local regex_neg='^ +'
|
|
||||||
|
|
||||||
while IFS='' read -r line
|
no_forbidden_patten "${file}" "${tempfile}" \
|
||||||
do
|
"Indent with tab" \
|
||||||
num="$((num + 1))"
|
'Replace tabs with 2 spaces instead.' \
|
||||||
if [[ "${line}" =~ ${regex_pos} && ! "${line}" =~ ${regex_neg} ]]
|
'^[[:space:]]+' \
|
||||||
then
|
'^ +'
|
||||||
onoe "Indent by tab detected at \"${file}\", line ${num}."
|
|
||||||
retcode=1
|
|
||||||
fi
|
|
||||||
done <"${file}"
|
|
||||||
return "${retcode}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check pattern:
|
# Check pattern:
|
||||||
@ -116,18 +134,10 @@ no_tabs() {
|
|||||||
no_multiline_for_statements() {
|
no_multiline_for_statements() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local tempfile="$2"
|
local tempfile="$2"
|
||||||
local line
|
|
||||||
local num=0
|
|
||||||
local retcode=0
|
|
||||||
local regex='^ *for [_[:alnum:]]+ in .*\\$'
|
local regex='^ *for [_[:alnum:]]+ in .*\\$'
|
||||||
|
local message
|
||||||
while IFS='' read -r line
|
message="$(
|
||||||
do
|
cat <<EOMSG
|
||||||
num="$((num + 1))"
|
|
||||||
if [[ "${line}" =~ ${regex} ]]
|
|
||||||
then
|
|
||||||
onoe "Multiline for statement detected at \"${file}\", line ${num}."
|
|
||||||
cat >&2 <<EOMSG
|
|
||||||
Use the followings instead (keep for statements only one line):
|
Use the followings instead (keep for statements only one line):
|
||||||
ARRAY=(
|
ARRAY=(
|
||||||
...
|
...
|
||||||
@ -137,10 +147,12 @@ Use the followings instead (keep for statements only one line):
|
|||||||
...
|
...
|
||||||
done
|
done
|
||||||
EOMSG
|
EOMSG
|
||||||
retcode=1
|
)"
|
||||||
fi
|
|
||||||
done <"${file}"
|
no_forbidden_patten "${file}" "${tempfile}" \
|
||||||
return "${retcode}"
|
"Multiline for statement" \
|
||||||
|
"${message}" \
|
||||||
|
"${regex}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check pattern:
|
# Check pattern:
|
||||||
@ -155,32 +167,26 @@ EOMSG
|
|||||||
no_IFS_newline() {
|
no_IFS_newline() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local tempfile="$2"
|
local tempfile="$2"
|
||||||
local line
|
|
||||||
local num=0
|
|
||||||
local retcode=0
|
|
||||||
local regex="^[^#]*IFS=\\\$'\\\\n'"
|
local regex="^[^#]*IFS=\\\$'\\\\n'"
|
||||||
|
local message
|
||||||
while IFS='' read -r line
|
message="$(
|
||||||
do
|
cat <<EOMSG
|
||||||
num="$((num + 1))"
|
|
||||||
if [[ "${line}" =~ ${regex} ]]
|
|
||||||
then
|
|
||||||
onoe "Pattern \`IFS=\$'\\n'\` detected at \"${file}\", line ${num}."
|
|
||||||
cat >&2 <<EOMSG
|
|
||||||
Use the followings instead:
|
Use the followings instead:
|
||||||
while IFS='' read -r line
|
while IFS='' read -r line
|
||||||
do
|
do
|
||||||
...
|
...
|
||||||
done < <(command)
|
done < <(command)
|
||||||
EOMSG
|
EOMSG
|
||||||
retcode=1
|
)"
|
||||||
fi
|
|
||||||
done <"${file}"
|
no_forbidden_patten "${file}" "${tempfile}" \
|
||||||
return "${retcode}"
|
"Pattern \`IFS=\$'\\n'\`" \
|
||||||
|
"${message}" \
|
||||||
|
"${regex}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Combine all forbidden styles
|
# Combine all forbidden styles
|
||||||
no_forbiddens() {
|
no_forbidden_styles() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local tempfile="$2"
|
local tempfile="$2"
|
||||||
|
|
||||||
@ -196,18 +202,23 @@ no_forbiddens() {
|
|||||||
# then then
|
# then then
|
||||||
#
|
#
|
||||||
# before: after:
|
# before: after:
|
||||||
# if [[ -n ... || \ if [[ -n ... || \
|
# if [[ -n ... || if [[ -n ... ||
|
||||||
# -n ... ]] -n ... ]]
|
# -n ... ]] -n ... ]]
|
||||||
# then then
|
# then then
|
||||||
#
|
#
|
||||||
align_multiline_if_condition() {
|
align_multiline_if_condition() {
|
||||||
local multiline_if_begin_regex='^( *)(el)?if '
|
|
||||||
local multiline_then_end_regex='^(.*)\; (then( *#.*)?)$'
|
|
||||||
local within_test_regex='^( *)(((! )?-[fdrwxes])|([^\[]+ == ))'
|
|
||||||
local base_indent=''
|
|
||||||
local extra_indent=''
|
|
||||||
local line
|
local line
|
||||||
local lastline=''
|
local lastline=''
|
||||||
|
local base_indent='' # indents before `if`
|
||||||
|
local extra_indent='' # 2 extra spaces for `elif`
|
||||||
|
local multiline_if_begin_regex='^( *)(el)?if '
|
||||||
|
local multiline_then_end_regex='^(.*)\; (then( *#.*)?)$'
|
||||||
|
local within_test_regex='^( *)(((! )?-[fdLrwxeszn] )|([^\[]+ == ))'
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
[[ "$1" =~ [^[:space:]](.*[^[:space:]])? ]]
|
||||||
|
printf "%s" "${BASH_REMATCH[0]}"
|
||||||
|
}
|
||||||
|
|
||||||
if [[ "$1" =~ ${multiline_if_begin_regex} ]]
|
if [[ "$1" =~ ${multiline_if_begin_regex} ]]
|
||||||
then
|
then
|
||||||
@ -228,9 +239,9 @@ align_multiline_if_condition() {
|
|||||||
fi
|
fi
|
||||||
if [[ "${line}" =~ ${within_test_regex} ]]
|
if [[ "${line}" =~ ${within_test_regex} ]]
|
||||||
then
|
then
|
||||||
echo " ${extra_indent}${line}"
|
echo "${base_indent}${extra_indent} $(trim "${line}")"
|
||||||
else
|
else
|
||||||
echo " ${extra_indent}${line}"
|
echo "${base_indent}${extra_indent} $(trim "${line}")"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -244,7 +255,7 @@ align_multiline_if_condition() {
|
|||||||
#
|
#
|
||||||
# before: after:
|
# before: after:
|
||||||
# if [[ ... ]] || if [[ ... ]] ||
|
# if [[ ... ]] || if [[ ... ]] ||
|
||||||
# [[ ... ]]; then [[ ... ]]
|
# [[ ... ]]; then [[ ... ]]
|
||||||
# then
|
# then
|
||||||
#
|
#
|
||||||
# before: after:
|
# before: after:
|
||||||
@ -255,13 +266,13 @@ wrap_then_do() {
|
|||||||
local file="$1"
|
local file="$1"
|
||||||
local tempfile="$2"
|
local tempfile="$2"
|
||||||
|
|
||||||
local -a processed
|
local -a processed=()
|
||||||
|
local -a buffer=()
|
||||||
local line
|
local line
|
||||||
local singleline_then_regex='^( *)(el)?if (.+)\; (then( *#.*)?)$'
|
local singleline_then_regex='^( *)(el)?if (.+)\; (then( *#.*)?)$'
|
||||||
local singleline_do_regex='^( *)(for|while) (.+)\; (do( *#.*)?)$'
|
local singleline_do_regex='^( *)(for|while) (.+)\; (do( *#.*)?)$'
|
||||||
local multiline_if_begin_regex='^( *)(el)?if '
|
local multiline_if_begin_regex='^( *)(el)?if '
|
||||||
local multiline_then_end_regex='^(.*)\; (then( *#.*)?)$'
|
local multiline_then_end_regex='^(.*)\; (then( *#.*)?)$'
|
||||||
local -a buffer=()
|
|
||||||
|
|
||||||
while IFS='' read -r line
|
while IFS='' read -r line
|
||||||
do
|
do
|
||||||
@ -297,22 +308,21 @@ wrap_then_do() {
|
|||||||
printf "%s\n" "${processed[@]}" >"${tempfile}"
|
printf "%s\n" "${processed[@]}" >"${tempfile}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: it's hard to align multiline switch cases
|
# TODO: It's hard to align multiline switch cases
|
||||||
align_multiline_switch_cases() {
|
align_multiline_switch_cases() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
format() {
|
format() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
|
local tempfile
|
||||||
if [[ ! -f "${file}" || ! -r "${file}" ]]
|
if [[ ! -f "${file}" || ! -r "${file}" ]]
|
||||||
then
|
then
|
||||||
onoe "File \"${file}\" is not readable."
|
onoe "File \"${file}\" is not readable."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# shellcheck disable=SC2155
|
tempfile="$(dirname "${file}")/.${file##*/}.temp"
|
||||||
local tempfile="$(dirname "${file}")/.${file##*/}.temp"
|
|
||||||
|
|
||||||
trap 'rm -f "${tempfile}" 2>/dev/null' RETURN
|
trap 'rm -f "${tempfile}" 2>/dev/null' RETURN
|
||||||
cp -af "${file}" "${tempfile}"
|
cp -af "${file}" "${tempfile}"
|
||||||
|
|
||||||
@ -325,15 +335,12 @@ format() {
|
|||||||
# Format with `shfmt` first
|
# Format with `shfmt` first
|
||||||
if ! "${SHFMT}" -w "${SHFMT_ARGS[@]}" "${tempfile}"
|
if ! "${SHFMT}" -w "${SHFMT_ARGS[@]}" "${tempfile}"
|
||||||
then
|
then
|
||||||
onoe "Failed to run \`shfmt\`"
|
onoe "Failed to run \`shfmt\` for file \"${file}\"."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Fail fast when forbidden patterns detected
|
# Fail fast when forbidden styles detected
|
||||||
if ! no_forbiddens "${file}" "${tempfile}"
|
! no_forbidden_styles "${file}" "${tempfile}" && return 2
|
||||||
then
|
|
||||||
return 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Tweak it with custom shell script styles
|
# Tweak it with custom shell script styles
|
||||||
wrap_then_do "${file}" "${tempfile}"
|
wrap_then_do "${file}" "${tempfile}"
|
||||||
@ -357,13 +364,15 @@ format() {
|
|||||||
RETCODE=0
|
RETCODE=0
|
||||||
for file in "${FILES[@]}"
|
for file in "${FILES[@]}"
|
||||||
do
|
do
|
||||||
if ! format "${file}"
|
format "${file}"
|
||||||
|
retcode="$?"
|
||||||
|
if [[ "${retcode}" != 0 ]]
|
||||||
then
|
then
|
||||||
if [[ "$?" == 1 ]]
|
if [[ "${retcode}" == 1 ]]
|
||||||
then
|
then
|
||||||
onoe "${0##*/}: Failed to format file \"${file}\". Function exited with code 1."
|
onoe "${0##*/}: Failed to format file \"${file}\". Formatter exited with code 1."
|
||||||
else
|
else
|
||||||
onoe "${0##*/}: Bad style for file \"${file}\". Function exited with code 2."
|
onoe "${0##*/}: Bad style for file \"${file}\". Formatter exited with code 2."
|
||||||
fi
|
fi
|
||||||
onoe
|
onoe
|
||||||
RETCODE=1
|
RETCODE=1
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user