Skip to content

Commit d5de5f6

Browse files
committed
tools: Update tidy.sh
1 parent afceb72 commit d5de5f6

File tree

1 file changed

+89
-36
lines changed

1 file changed

+89
-36
lines changed

tools/tidy.sh

Lines changed: 89 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/usr/bin/env bash
22
# SPDX-License-Identifier: Apache-2.0 OR MIT
3-
# shellcheck disable=SC2046
43
set -CeEuo pipefail
54
IFS=$'\n\t'
65
trap -- 's=$?; printf >&2 "%s\n" "${0##*/}:${LINENO}: \`${BASH_COMMAND}\` exit with ${s}"; exit ${s}' ERR
@@ -14,7 +13,7 @@ cd -- "$(dirname -- "$0")"/..
1413
# - git 1.8+
1514
# - jq 1.6+
1615
# - npm (node 18+)
17-
# - python 3.6+ and pipx
16+
# - python 3.6+, pipx
1817
# - shfmt
1918
# - shellcheck
2019
# - zizmor
@@ -71,7 +70,7 @@ check_diff() {
7170
fi
7271
else
7372
local res
74-
res=$(git --no-pager diff --exit-code --name-only "$@" || true)
73+
res=$(git --no-pager diff --name-only "$@")
7574
if [[ -n "${res}" ]]; then
7675
warn "please commit changes made by formatter/generator if exists on the following files"
7776
print_fenced "${res}"$'\n'
@@ -116,7 +115,6 @@ check_alt() {
116115
fi
117116
}
118117
check_hidden() {
119-
local res
120118
for file in "$@"; do
121119
check_alt ".${file}" "${file}" "$(LC_ALL=C comm -23 <(ls_files "*${file}") <(ls_files "*.${file}"))"
122120
done
@@ -125,6 +123,7 @@ sed_rhs_escape() {
125123
sed -E 's/\\/\\\\/g; s/\&/\\\&/g; s/\//\\\//g' <<<"$1"
126124
}
127125

126+
should_fail=''
128127
if [[ $# -gt 0 ]]; then
129128
cat <<EOF
130129
USAGE:
@@ -174,14 +173,19 @@ case "$(uname -s)" in
174173
done
175174
fi
176175
;;
176+
Haiku) ostype=haiku ;;
177+
Minix) ostype=minix ;;
178+
GNU) ostype=hurd ;;
179+
AIX) ostype=aix ;;
180+
HP-UX) ostype=hpux ;;
177181
MINGW* | MSYS* | CYGWIN* | Windows_NT)
178182
ostype=windows
179183
if type -P jq >/dev/null; then
180184
# https://github.com/jqlang/jq/issues/1854
181-
_tmp=$(jq -r .a <<<'{}')
182-
if [[ "${_tmp}" != 'null' ]]; then
183-
_tmp=$(jq -b -r .a 2>/dev/null <<<'{}' || true)
184-
if [[ "${_tmp}" == 'null' ]]; then
185+
_tmp=$(jq -r .a <<<'{}' | wc -c)
186+
if [[ "${_tmp}" != 5 ]]; then
187+
_tmp=$({ jq -b -r .a 2>/dev/null <<<'{}' || true; } | wc -c)
188+
if [[ "${_tmp}" == 5 ]]; then
185189
jq() { command jq -b "$@"; }
186190
else
187191
jq() { command jq "$@" | tr -d '\r'; }
@@ -195,7 +199,6 @@ case "$(uname -s)" in
195199
esac
196200

197201
check_install git
198-
exclude_from_ls_files=()
199202
# - `find` lists symlinks. `! ( -name <dir> -prune )` means recursively ignore <dir>. `cut` removes the leading `./`.
200203
# This can be replaced with `fd -H -t l`.
201204
# - `git submodule status` lists submodules. The first `cut` removes the first character indicates status ( |+|-).
@@ -204,6 +207,7 @@ find_prune=(\! \( -name .git -prune \))
204207
while IFS= read -r; do
205208
find_prune+=(\! \( -name "${REPLY}" -prune \))
206209
done < <(sed -E 's/#.*//g; s/^[ \t]+//g; s/\/[ \t]+$//g; /^$/d' .gitignore)
210+
exclude_from_ls_files=()
207211
while IFS=$'\n' read -r; do
208212
exclude_from_ls_files+=("${REPLY}")
209213
done < <({
@@ -227,12 +231,24 @@ ls_files() {
227231
fi
228232
}
229233

234+
# Referred by both Rust and Markdown check.
235+
markdown_files=()
236+
while IFS=$'\n' read -r; do markdown_files+=("${REPLY}"); done < <(ls_files '*.md')
237+
if [[ ${TIDY_EXPECTED_MARKDOWN_FILE_COUNT:-${#markdown_files[@]}} -ne ${#markdown_files[@]} ]]; then
238+
error "expected ${TIDY_EXPECTED_MARKDOWN_FILE_COUNT} of Markdown files, but found ${#markdown_files[@]}; consider updating TIDY_EXPECTED_MARKDOWN_FILE_COUNT env var"
239+
fi
240+
230241
# Rust (if exists)
231-
if [[ -n "$(ls_files '*.rs')" ]]; then
242+
rust_files=()
243+
while IFS=$'\n' read -r; do rust_files+=("${REPLY}"); done < <(ls_files '*.rs')
244+
if [[ ${TIDY_EXPECTED_RUST_FILE_COUNT:-${#rust_files[@]}} -ne ${#rust_files[@]} ]]; then
245+
error "expected ${TIDY_EXPECTED_RUST_FILE_COUNT} of Rust files, but found ${#rust_files[@]}; consider updating TIDY_EXPECTED_RUST_FILE_COUNT env var"
246+
fi
247+
if [[ ${#rust_files[@]} -gt 0 ]]; then
232248
info "checking Rust code style"
233249
check_config .rustfmt.toml "; consider adding with reference to https://github.com/taiki-e/cargo-hack/blob/HEAD/.rustfmt.toml"
234250
check_config .clippy.toml "; consider adding with reference to https://github.com/taiki-e/cargo-hack/blob/HEAD/.clippy.toml"
235-
if check_install cargo jq python3 pipx; then
251+
if check_install cargo jq pipx; then
236252
# `cargo fmt` cannot recognize files not included in the current workspace and modules
237253
# defined inside macros, so run rustfmt directly.
238254
# We need to use nightly rustfmt because we use the unstable formatting options of rustfmt.
@@ -242,16 +258,16 @@ if [[ -n "$(ls_files '*.rs')" ]]; then
242258
retry rustup component add rustfmt &>/dev/null
243259
fi
244260
info "running \`rustfmt \$(git ls-files '*.rs')\`"
245-
rustfmt $(ls_files '*.rs')
261+
rustfmt "${rust_files[@]}"
246262
else
247263
if type -P rustup >/dev/null; then
248264
retry rustup component add rustfmt --toolchain nightly &>/dev/null
249265
fi
250266
info "running \`rustfmt +nightly \$(git ls-files '*.rs')\`"
251-
rustfmt +nightly $(ls_files '*.rs')
267+
rustfmt +nightly "${rust_files[@]}"
252268
fi
253-
check_diff $(ls_files '*.rs')
254-
cast_without_turbofish=$(grep -Fn '.cast()' $(ls_files '*.rs') || true)
269+
check_diff "${rust_files[@]}"
270+
cast_without_turbofish=$(grep -Fn '.cast()' "${rust_files[@]}" || true)
255271
if [[ -n "${cast_without_turbofish}" ]]; then
256272
error "please replace \`.cast()\` with \`.cast::<type_name>()\`:"
257273
printf '%s\n' "${cast_without_turbofish}"
@@ -332,7 +348,7 @@ if [[ -n "$(ls_files '*.rs')" ]]; then
332348
fi
333349
# Sync markdown to rustdoc.
334350
first=1
335-
for markdown in $(ls_files '*.md'); do
351+
for markdown in "${markdown_files[@]}"; do
336352
markers=$(grep -En '^<!-- tidy:sync-markdown-to-rustdoc:(start[^ ]*|end) -->' "${markdown}" || true)
337353
# BSD wc's -l emits spaces before number.
338354
if [[ ! "$(LC_ALL=C wc -l <<<"${markers}")" =~ ^\ *2$ ]]; then
@@ -381,10 +397,11 @@ if [[ -n "$(ls_files '*.rs')" ]]; then
381397
fi
382398
new='<!-- tidy:sync-markdown-to-rustdoc:start -->'$'\a'
383399
empty_line_re='^ *$'
384-
gfm_alert_re='^> {0,4}\[!.*\] *$'
400+
gfm_alert_re='^ *> {0,4}\[!.*\] *$'
385401
rust_code_block_re='^ *```(rust|rs) *$'
386402
code_block_attr=''
387403
in_alert=''
404+
leading_spaces=''
388405
first_line=1
389406
ignore=''
390407
while IFS='' read -rd$'\a' line; do
@@ -401,7 +418,7 @@ if [[ -n "$(ls_files '*.rs')" ]]; then
401418
elif [[ -n "${in_alert}" ]]; then
402419
if [[ "${line}" =~ ${empty_line_re} ]]; then
403420
in_alert=''
404-
new+=$'\a'"</div>"$'\a'
421+
new+=$'\a'"${leading_spaces}</div>"$'\a'
405422
fi
406423
elif [[ "${line}" =~ ${gfm_alert_re} ]]; then
407424
alert="${line#*[\!}"
@@ -418,8 +435,13 @@ if [[ -n "$(ls_files '*.rs')" ]]; then
418435
;;
419436
esac
420437
in_alert=1
421-
new+="<div class=\"rustdoc-alert rustdoc-alert-${alert_lower}\">"$'\a\a'
422-
new+="> **${alert_sign} ${alert:0:1}${alert_lower:1}**"$'\a>\a'
438+
leading_spaces="${line%%[^ ]*}"
439+
# GitHub doesn't handle indented GFM alerts...
440+
if [[ -n "${leading_spaces}" ]]; then
441+
error "GitHub doesn't handle indented GFM alerts"
442+
fi
443+
new+="${leading_spaces}<div class=\"rustdoc-alert rustdoc-alert-${alert_lower}\">"$'\a\a'
444+
new+="${leading_spaces}> **${alert_sign} ${alert:0:1}${alert_lower:1}**"$'\a'"${leading_spaces}>"$'\a'
423445
continue
424446
fi
425447
if [[ "${line}" =~ ${rust_code_block_re} ]]; then
@@ -459,15 +481,20 @@ check_hidden clippy.toml deny.toml rustfmt.toml
459481

460482
# C/C++/Protobuf (if exists)
461483
clang_format_ext=('*.c' '*.h' '*.cpp' '*.hpp' '*.proto')
462-
if [[ -n "$(ls_files "${clang_format_ext[@]}")" ]]; then
484+
clang_format_files=()
485+
while IFS=$'\n' read -r; do clang_format_files+=("${REPLY}"); done < <(ls_files "${clang_format_ext[@]}")
486+
if [[ ${TIDY_EXPECTED_CLANG_FORMAT_FILE_COUNT:-${#clang_format_files[@]}} -ne ${#clang_format_files[@]} ]]; then
487+
error "expected ${TIDY_EXPECTED_CLANG_FORMAT_FILE_COUNT} of C/C++/Protobuf files, but found ${#clang_format_files[@]}; consider updating TIDY_EXPECTED_CLANG_FORMAT_FILE_COUNT env var"
488+
fi
489+
if [[ ${#clang_format_files[@]} -gt 0 ]]; then
463490
info "checking C/C++/Protobuf code style"
464491
check_config .clang-format
465492
if check_install clang-format; then
466493
IFS=' '
467494
info "running \`clang-format -i \$(git ls-files ${clang_format_ext[*]})\`"
468495
IFS=$'\n\t'
469-
clang-format -i $(ls_files "${clang_format_ext[@]}")
470-
check_diff $(ls_files "${clang_format_ext[@]}")
496+
clang-format -i "${clang_format_files[@]}"
497+
check_diff "${clang_format_files[@]}"
471498
fi
472499
printf '\n'
473500
else
@@ -480,15 +507,20 @@ check_alt '.hpp extension' 'other extensions' "$(ls_files '*.hh' '*.hp' '*.hxx'
480507

481508
# YAML/HTML/CSS/JavaScript/JSON (if exists)
482509
prettier_ext=('*.css' '*.html' '*.js' '*.json' '*.yml' '*.yaml')
483-
if [[ -n "$(ls_files "${prettier_ext[@]}")" ]]; then
510+
prettier_files=()
511+
while IFS=$'\n' read -r; do prettier_files+=("${REPLY}"); done < <(ls_files "${prettier_ext[@]}")
512+
if [[ ${TIDY_EXPECTED_PRETTIER_FILE_COUNT:-${#prettier_files[@]}} -ne ${#prettier_files[@]} ]]; then
513+
error "expected ${TIDY_EXPECTED_PRETTIER_FILE_COUNT} of YAML/HTML/CSS/JavaScript/JSON files, but found ${#prettier_files[@]}; consider updating TIDY_EXPECTED_PRETTIER_FILE_COUNT env var"
514+
fi
515+
if [[ ${#prettier_files[@]} -gt 0 ]]; then
484516
info "checking YAML/HTML/CSS/JavaScript/JSON code style"
485517
check_config .editorconfig
486518
if check_install npm; then
487519
IFS=' '
488520
info "running \`npx -y prettier -l -w \$(git ls-files ${prettier_ext[*]})\`"
489521
IFS=$'\n\t'
490-
npx -y prettier -l -w $(ls_files "${prettier_ext[@]}")
491-
check_diff $(ls_files "${prettier_ext[@]}")
522+
npx -y prettier -l -w "${prettier_files[@]}"
523+
check_diff "${prettier_files[@]}"
492524
fi
493525
printf '\n'
494526
else
@@ -499,13 +531,18 @@ check_alt '.editorconfig' 'other configs' "$(ls_files '*.prettierrc*' '*prettier
499531
check_alt '.yml extension' '.yaml extension' "$(ls_files '*.yaml' | { grep -Fv '.markdownlint-cli2.yaml' || true; })"
500532

501533
# TOML (if exists)
534+
toml_files=()
535+
while IFS=$'\n' read -r; do toml_files+=("${REPLY}"); done < <(ls_files '*.toml')
536+
if [[ ${TIDY_EXPECTED_TOML_FILE_COUNT:-${#toml_files[@]}} -ne ${#toml_files[@]} ]]; then
537+
error "expected ${TIDY_EXPECTED_TOML_FILE_COUNT} of TOML files, but found ${#toml_files[@]}; consider updating TIDY_EXPECTED_TOML_FILE_COUNT env var"
538+
fi
502539
if [[ -n "$(ls_files '*.toml' | { grep -Fv '.taplo.toml' || true; })" ]]; then
503540
info "checking TOML style"
504541
check_config .taplo.toml
505542
if check_install npm; then
506543
info "running \`npx -y @taplo/cli fmt \$(git ls-files '*.toml')\`"
507-
RUST_LOG=warn npx -y @taplo/cli fmt $(ls_files '*.toml')
508-
check_diff $(ls_files '*.toml')
544+
RUST_LOG=warn npx -y @taplo/cli fmt "${toml_files[@]}"
545+
check_diff "${toml_files[@]}"
509546
fi
510547
printf '\n'
511548
else
@@ -514,12 +551,12 @@ fi
514551
check_hidden taplo.toml
515552

516553
# Markdown (if exists)
517-
if [[ -n "$(ls_files '*.md')" ]]; then
554+
if [[ ${#markdown_files[@]} -gt 0 ]]; then
518555
info "checking markdown style"
519556
check_config .markdownlint-cli2.yaml
520557
if check_install npm; then
521558
info "running \`npx -y markdownlint-cli2 \$(git ls-files '*.md')\`"
522-
if ! npx -y markdownlint-cli2 $(ls_files '*.md'); then
559+
if ! npx -y markdownlint-cli2 "${markdown_files[@]}"; then
523560
error "check failed; please resolve the above markdownlint error(s)"
524561
fi
525562
fi
@@ -580,6 +617,12 @@ if [[ -n "$(ls_files '*action.yml')" ]]; then
580617
fi
581618
done
582619
fi
620+
if [[ ${TIDY_EXPECTED_SHELL_FILE_COUNT:-${#shell_files[@]}} -ne ${#shell_files[@]} ]]; then
621+
error "expected ${TIDY_EXPECTED_SHELL_FILE_COUNT} of shell script files, but found ${#shell_files[@]}; consider updating TIDY_EXPECTED_SHELL_FILE_COUNT env var"
622+
fi
623+
if [[ ${TIDY_EXPECTED_DOCKER_FILE_COUNT:-${#docker_files[@]}} -ne ${#docker_files[@]} ]]; then
624+
error "expected ${TIDY_EXPECTED_DOCKER_FILE_COUNT} of dockerfiles, but found ${#docker_files[@]}; consider updating TIDY_EXPECTED_DOCKER_FILE_COUNT env var"
625+
fi
583626
# correctness
584627
res=$({ grep -En '(\[\[ .* ]]|(^|[^\$])\(\(.*\)\))( +#| *$)' "${bash_files[@]}" || true; } | { grep -Ev '^[^ ]+: *(#|//)' || true; } | LC_ALL=C sort)
585628
if [[ -n "${res}" ]]; then
@@ -851,10 +894,19 @@ EOF
851894
for job in $(jq -c '.jobs | to_entries[] | select(.value.steps)' <<<"${workflow}"); do
852895
name=$(jq -r '.key' <<<"${job}")
853896
job=$(jq -r '.value' <<<"${job}")
897+
eval "$(jq -r '@sh "RUNS_ON=\(."runs-on") TIMEOUT_MINUTES=\(."timeout-minutes") JOB_DEFAULT_SHELL=\(.defaults.run.shell)"' <<<"${job}")"
898+
if [[ "${TIMEOUT_MINUTES}" == 'null' ]]; then
899+
error ".jobs.${name}.timeout-minutes must be set"
900+
fi
901+
if [[ "${RUNS_ON}" == 'ubuntu-slim' ]]; then
902+
case "${TIMEOUT_MINUTES}" in
903+
? | 1[0-5]) ;;
904+
*) error ".jobs.${name}.timeout-minutes must be <= 15 because max execution time of ubuntu-slim runner is 15 minutes" ;;
905+
esac
906+
fi
854907
n=0
855-
job_default_shell=$(jq -r '.defaults.run.shell' <<<"${job}")
856-
if [[ "${job_default_shell}" == 'null' ]]; then
857-
job_default_shell="${default_shell}"
908+
if [[ "${JOB_DEFAULT_SHELL}" == 'null' ]]; then
909+
JOB_DEFAULT_SHELL="${default_shell}"
858910
fi
859911
for step in $(jq -c '.steps[]' <<<"${job}"); do
860912
prepare=''
@@ -865,7 +917,7 @@ EOF
865917
fi
866918
if [[ "${shell}" == 'null' ]]; then
867919
if [[ -z "${prepare}" ]]; then
868-
shell="${job_default_shell}"
920+
shell="${JOB_DEFAULT_SHELL}"
869921
elif grep -Eq '^ *chsh +-s +[^ ]+/bash' <<<"${prepare}"; then
870922
shell='bash'
871923
else
@@ -917,6 +969,7 @@ if [[ ${#zizmor_targets[@]} -gt 0 ]]; then
917969
if [[ "${ostype}" =~ ^(netbsd|openbsd|dragonfly|illumos|solaris)$ ]] && [[ -n "${CI:-}" ]] && ! type -P zizmor >/dev/null; then
918970
warn "this check is skipped on NetBSD/OpenBSD/Dragonfly/illumos/Solaris due to installing zizmor is hard on these platform"
919971
elif check_install zizmor; then
972+
# zizmor can also be used via pipx, but old version will be installed if glibc version is old.
920973
IFS=' '
921974
info "running \`zizmor -q ${zizmor_targets[*]}\`"
922975
IFS=$'\n\t'
@@ -931,7 +984,7 @@ check_alt '.sh extension' '*.bash extension' "$(ls_files '*.bash')"
931984
if [[ -f tools/.tidy-check-license-headers ]]; then
932985
info "checking license headers (experimental)"
933986
failed_files=''
934-
for p in $(LC_ALL=C comm -12 <(eval $(<tools/.tidy-check-license-headers) | LC_ALL=C sort) <(ls_files | LC_ALL=C sort)); do
987+
for p in $(LC_ALL=C comm -12 <(eval "$(<tools/.tidy-check-license-headers)" | LC_ALL=C sort) <(ls_files | LC_ALL=C sort)); do
935988
case "${p##*/}" in
936989
*.stderr | *.expanded.rs) continue ;; # generated files
937990
*.json) continue ;; # no comment support
@@ -973,7 +1026,7 @@ fi
9731026
if [[ -f .cspell.json ]]; then
9741027
info "spell checking"
9751028
project_dictionary=.github/.cspell/project-dictionary.txt
976-
if check_install npm jq python3 pipx; then
1029+
if check_install npm jq pipx; then
9771030
has_rust=''
9781031
if [[ -n "$(ls_files '*Cargo.toml')" ]]; then
9791032
has_rust=1

0 commit comments

Comments
 (0)