From c8c9618a73f383f405364b352558db3158969f88 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Mon, 8 Sep 2025 08:34:55 +0100 Subject: [PATCH 1/7] reinvoke script to run tool --- scripts/githooks/check-file-format.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/githooks/check-file-format.sh b/scripts/githooks/check-file-format.sh index d7c94747..868d7d53 100755 --- a/scripts/githooks/check-file-format.sh +++ b/scripts/githooks/check-file-format.sh @@ -41,6 +41,14 @@ set -euo pipefail # ============================================================================== function main() { + if [[ ${#@} != 0 ]] && declare -f "main-tool-wrapper$1" >/dev/null 2>&1 ; then + "main-tool-wrapper$1" "${@:2}" + else + main-invocation "$@" + fi +} + +function main-invocation() { cd "$(git rev-parse --show-toplevel)" @@ -67,9 +75,9 @@ function main() { esac if command -v editorconfig > /dev/null 2>&1 && ! is-arg-true "${FORCE_USE_DOCKER:-false}"; then - filter="$filter" dry_run_opt="${dry_run_opt:-}" run-editorconfig-natively + filter="$filter" dry_run_opt="${dry_run_opt:-}" scripts/githooks/check-file-format.sh --natively else - filter="$filter" dry_run_opt="${dry_run_opt:-}" run-editorconfig-in-docker + filter="$filter" dry_run_opt="${dry_run_opt:-}" scripts/githooks/check-file-format.sh --via-docker fi } @@ -77,7 +85,7 @@ function main() { # Arguments (provided as environment variables): # dry_run_opt=[dry run option] # filter=[git command to filter the files to check] -function run-editorconfig-natively() { +function main-tool-wrapper--natively() { # shellcheck disable=SC2046,SC2086 editorconfig \ @@ -88,7 +96,7 @@ function run-editorconfig-natively() { # Arguments (provided as environment variables): # dry_run_opt=[dry run option] # filter=[git command to filter the files to check] -function run-editorconfig-in-docker() { +function main-tool-wrapper--via-docker() { # shellcheck disable=SC1091 source ./scripts/docker/docker.lib.sh From c1a37511556229b5ec8b14def16fa1540a6b6afe Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Mon, 8 Sep 2025 08:43:17 +0100 Subject: [PATCH 2/7] factor out call to tool --- scripts/githooks/check-file-format.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/githooks/check-file-format.sh b/scripts/githooks/check-file-format.sh index 868d7d53..24ca2406 100755 --- a/scripts/githooks/check-file-format.sh +++ b/scripts/githooks/check-file-format.sh @@ -75,10 +75,12 @@ function main-invocation() { esac if command -v editorconfig > /dev/null 2>&1 && ! is-arg-true "${FORCE_USE_DOCKER:-false}"; then - filter="$filter" dry_run_opt="${dry_run_opt:-}" scripts/githooks/check-file-format.sh --natively + method=--natively else - filter="$filter" dry_run_opt="${dry_run_opt:-}" scripts/githooks/check-file-format.sh --via-docker + method=--via-docker fi + + filter="$filter" dry_run_opt="${dry_run_opt:-}" scripts/githooks/check-file-format.sh "$method" } # Run editorconfig natively. From 77c82e0349fbb574db6e601e54970106cf7e2a0a Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Mon, 8 Sep 2025 08:59:17 +0100 Subject: [PATCH 3/7] provide list of files directly to main-tool-wrapper--*, instead of command to provide list --- scripts/githooks/check-file-format.sh | 48 +++++++++++++++------------ 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/scripts/githooks/check-file-format.sh b/scripts/githooks/check-file-format.sh index 24ca2406..d1f5c3eb 100755 --- a/scripts/githooks/check-file-format.sh +++ b/scripts/githooks/check-file-format.sh @@ -56,23 +56,9 @@ function main-invocation() { is-arg-true "${dry_run:-false}" && dry_run_opt="--dry-run" check=${check:-working-tree-changes} - case $check in - "all") - filter="git ls-files" - ;; - "staged-changes") - filter="git diff --diff-filter=ACMRT --name-only --cached" - ;; - "working-tree-changes") - filter="git diff --diff-filter=ACMRT --name-only" - ;; - "branch") - filter="git diff --diff-filter=ACMRT --name-only ${BRANCH_NAME:-origin/main}" - ;; - *) - echo "Unrecognised check mode: $check" >&2 && exit 1 - ;; - esac + if ! declare -f "list-files-to-check--$check" >/dev/null 2>&1 ; then + echo "Unrecognised check mode: $check" >&2 && exit 1 + fi if command -v editorconfig > /dev/null 2>&1 && ! is-arg-true "${FORCE_USE_DOCKER:-false}"; then method=--natively @@ -80,24 +66,24 @@ function main-invocation() { method=--via-docker fi - filter="$filter" dry_run_opt="${dry_run_opt:-}" scripts/githooks/check-file-format.sh "$method" + dry_run_opt="${dry_run_opt:-}" scripts/githooks/check-file-format.sh "$method" $(list-files-to-check--"$check") } # Run editorconfig natively. # Arguments (provided as environment variables): # dry_run_opt=[dry run option] -# filter=[git command to filter the files to check] +# Arguments (provided as positional parameters): files to check function main-tool-wrapper--natively() { # shellcheck disable=SC2046,SC2086 editorconfig \ - --exclude '.git/' $dry_run_opt $($filter) + --exclude '.git/' $dry_run_opt "$@" } # Run editorconfig in a Docker container. # Arguments (provided as environment variables): # dry_run_opt=[dry run option] -# filter=[git command to filter the files to check] +# Arguments (provided as positional parameters): files to check function main-tool-wrapper--via-docker() { # shellcheck disable=SC1091 @@ -111,7 +97,25 @@ function main-tool-wrapper--via-docker() { docker run --rm --platform linux/amd64 \ --volume "$PWD":/check \ "$image" \ - sh -c "ec --exclude '.git/' $dry_run_opt \$($filter) /dev/null" + sh -c "ec --exclude '.git/' $dry_run_opt $(printf '%q ' "$@") /dev/null" +} + +# ============================================================================== + +function list-files-to-check--all() { + git ls-files +} + +function list-files-to-check--staged-changes() { + git diff --diff-filter=ACMRT --name-only --cached +} + +function list-files-to-check--working-tree-changes() { + git diff --diff-filter=ACMRT --name-only +} + +function list-files-to-check--branch() { + git diff --diff-filter=ACMRT --name-only ${BRANCH_NAME:-origin/main} } # ============================================================================== From 84cfdc10f6bdccae9c6e68c5c60236acd609d491 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Mon, 8 Sep 2025 09:05:18 +0100 Subject: [PATCH 4/7] split files into batches --- scripts/githooks/check-file-format.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/githooks/check-file-format.sh b/scripts/githooks/check-file-format.sh index d1f5c3eb..1cf26a34 100755 --- a/scripts/githooks/check-file-format.sh +++ b/scripts/githooks/check-file-format.sh @@ -66,7 +66,12 @@ function main-invocation() { method=--via-docker fi - dry_run_opt="${dry_run_opt:-}" scripts/githooks/check-file-format.sh "$method" $(list-files-to-check--"$check") + list-files-to-check--"$check" | + # Maximum size of command line and environment combined is typically + # 2MB on Linux but only 256KB on macOS. Assume a maximum filename + # length of 200 characters and limiting us to batches of 1000 files + # gives us a bit of a safety margin. + dry_run_opt="${dry_run_opt:-}" xargs --max-args=1000 scripts/githooks/check-file-format.sh "$method" } # Run editorconfig natively. From 18e19ba5b5bce98e3c6631448685dd57311a3da9 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Mon, 8 Sep 2025 09:06:56 +0100 Subject: [PATCH 5/7] use --no-run-if-empty to avoid empty batches --- scripts/githooks/check-file-format.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/githooks/check-file-format.sh b/scripts/githooks/check-file-format.sh index 1cf26a34..e99f92b6 100755 --- a/scripts/githooks/check-file-format.sh +++ b/scripts/githooks/check-file-format.sh @@ -71,7 +71,7 @@ function main-invocation() { # 2MB on Linux but only 256KB on macOS. Assume a maximum filename # length of 200 characters and limiting us to batches of 1000 files # gives us a bit of a safety margin. - dry_run_opt="${dry_run_opt:-}" xargs --max-args=1000 scripts/githooks/check-file-format.sh "$method" + dry_run_opt="${dry_run_opt:-}" xargs --max-args=1000 --no-run-if-empty scripts/githooks/check-file-format.sh "$method" } # Run editorconfig natively. @@ -96,13 +96,10 @@ function main-tool-wrapper--via-docker() { # shellcheck disable=SC2155 local image=$(name=mstruebing/editorconfig-checker docker-get-image-version-and-pull) - # We use /dev/null here as a backstop in case there are no files in the state - # we choose. If the filter comes back empty, adding `/dev/null` onto it has - # the effect of preventing `ec` from treating "no files" as "all the files". docker run --rm --platform linux/amd64 \ --volume "$PWD":/check \ "$image" \ - sh -c "ec --exclude '.git/' $dry_run_opt $(printf '%q ' "$@") /dev/null" + sh -c "ec --exclude '.git/' $dry_run_opt $(printf '%q ' "$@")" } # ============================================================================== From 1c9b277e5bf3a4785e53542f2a86c82ec3f58196 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Mon, 8 Sep 2025 09:09:27 +0100 Subject: [PATCH 6/7] terminate filenames with NUL, not LF --- scripts/githooks/check-file-format.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/githooks/check-file-format.sh b/scripts/githooks/check-file-format.sh index e99f92b6..021acad9 100755 --- a/scripts/githooks/check-file-format.sh +++ b/scripts/githooks/check-file-format.sh @@ -71,7 +71,7 @@ function main-invocation() { # 2MB on Linux but only 256KB on macOS. Assume a maximum filename # length of 200 characters and limiting us to batches of 1000 files # gives us a bit of a safety margin. - dry_run_opt="${dry_run_opt:-}" xargs --max-args=1000 --no-run-if-empty scripts/githooks/check-file-format.sh "$method" + dry_run_opt="${dry_run_opt:-}" xargs -0 --max-args=1000 --no-run-if-empty scripts/githooks/check-file-format.sh "$method" } # Run editorconfig natively. @@ -104,20 +104,23 @@ function main-tool-wrapper--via-docker() { # ============================================================================== +# These all produce filenames terminated by a NUL character, so that we +# can handle filenames that contain spaces. + function list-files-to-check--all() { - git ls-files + git ls-files -z } function list-files-to-check--staged-changes() { - git diff --diff-filter=ACMRT --name-only --cached + git diff -z --diff-filter=ACMRT --name-only --cached } function list-files-to-check--working-tree-changes() { - git diff --diff-filter=ACMRT --name-only + git diff -z --diff-filter=ACMRT --name-only } function list-files-to-check--branch() { - git diff --diff-filter=ACMRT --name-only ${BRANCH_NAME:-origin/main} + git diff -z --diff-filter=ACMRT --name-only ${BRANCH_NAME:-origin/main} } # ============================================================================== From c2c74345ebc873dd2ac523774ce36aef4ab25a74 Mon Sep 17 00:00:00 2001 From: Dave Hinton Date: Mon, 8 Sep 2025 09:16:50 +0100 Subject: [PATCH 7/7] rename functions --- scripts/githooks/check-file-format.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/githooks/check-file-format.sh b/scripts/githooks/check-file-format.sh index 021acad9..8ea0c142 100755 --- a/scripts/githooks/check-file-format.sh +++ b/scripts/githooks/check-file-format.sh @@ -41,8 +41,8 @@ set -euo pipefail # ============================================================================== function main() { - if [[ ${#@} != 0 ]] && declare -f "main-tool-wrapper$1" >/dev/null 2>&1 ; then - "main-tool-wrapper$1" "${@:2}" + if [[ ${#@} != 0 ]] && declare -f "run-editorconfig$1" >/dev/null 2>&1 ; then + "run-editorconfig$1" "${@:2}" else main-invocation "$@" fi @@ -78,7 +78,7 @@ function main-invocation() { # Arguments (provided as environment variables): # dry_run_opt=[dry run option] # Arguments (provided as positional parameters): files to check -function main-tool-wrapper--natively() { +function run-editorconfig--natively() { # shellcheck disable=SC2046,SC2086 editorconfig \ @@ -89,7 +89,7 @@ function main-tool-wrapper--natively() { # Arguments (provided as environment variables): # dry_run_opt=[dry run option] # Arguments (provided as positional parameters): files to check -function main-tool-wrapper--via-docker() { +function run-editorconfig--via-docker() { # shellcheck disable=SC1091 source ./scripts/docker/docker.lib.sh