| #!/usr/bin/env bash |
| |
| # src/tools/fmt |
| |
| set -e -u -o pipefail |
| |
| # This script formats (or checks) C++ code with clang-format in the following |
| # locations: |
| # |
| # src/backend/gpopt |
| # src/include/gpopt |
| # src/backend/gporca |
| # |
| # To generate the expanded configuration file for a change in intent: |
| # $ fmt gen |
| # |
| # To format all ORCA / GPOPT code: |
| # $ fmt fmt |
| # |
| # To check for formatting conformance: |
| # $ fmt chk |
| # |
| # If the name of your clang-format executable isn't "clang-format", you can |
| # override it in the CLANG_FORMAT environment variable. |
| # |
| # For more about ORCA's format, see src/backend/gporca/README.format.md |
| |
| |
| # we use mapfile from Bash 4.0, but it's sufficiently likely that *someone* on |
| # a macOS system would be using Bash 3.2 that it'd be unkind not to guard |
| # against it. |
| if ((BASH_VERSINFO[0] < 4)); then false; fi |
| |
| readonly INTENT=src/backend/gporca/clang-format.intent.yaml |
| : "${CLANG_FORMAT:=clang-format}" |
| |
| gen() { |
| local DIR |
| DIR=$(mktemp -d -t orca-clang-format.XXX) |
| cp "${INTENT}" "${DIR}/.clang-format" |
| |
| local -a CLANG_FORMAT_CONFIG_FILES |
| # do not squish the assignment into the declaration, as that will swallow |
| # errors in the subshell |
| local _find_result |
| _find_result=$(find src/backend/gporca -name .clang-format) |
| mapfile -t CLANG_FORMAT_CONFIG_FILES <<<$_find_result |
| |
| ( |
| set -e |
| cd "${DIR}" |
| "${CLANG_FORMAT}" -style=file -dump-config >clang-format.yaml |
| ) |
| |
| for cf in "${CLANG_FORMAT_CONFIG_FILES[@]}"; do |
| cp -v "${DIR}/clang-format.yaml" "${cf}" |
| done |
| rm -r "${DIR}" |
| } |
| |
| # NUL-delimited list of files to format |
| files_to_format() { |
| local -a CLANG_FORMAT_CONFIG_FILES |
| # do not squish the assignment into the declaration, as that will swallow |
| # errors in the subshell |
| local _find_result |
| _find_result=$(find src/backend/gporca src/backend/gpopt src/include/gpopt -name .clang-format) |
| mapfile -t CLANG_FORMAT_CONFIG_FILES <<<$_find_result |
| |
| local -a CF_DIRS PATTERNS |
| CF_DIRS=("${CLANG_FORMAT_CONFIG_FILES[@]%/*}") |
| PATTERNS=("${CF_DIRS[@]/%/\/*.cpp}" "${CF_DIRS[@]/%/\/*.h}") |
| git ls-files -z "${PATTERNS[@]}" |
| } |
| |
| # This depends on GNU parallel (https://www.gnu.org/software/parallel/). To install: |
| # macOS: brew install parallel |
| # Debian-derivatives: apt install parallel |
| fmt() { |
| files_to_format | parallel -n64 -P +0 -0 \ |
| "${CLANG_FORMAT}" -i |
| } |
| |
| chk() { |
| # --tty: enables colorful diagnostics |
| # --halt: fail as soon as we encounter the first formatting diagnostic |
| files_to_format | parallel -n64 -P +0 -0 \ |
| --halt now,fail=1 --tty \ |
| "${CLANG_FORMAT}" -dry-run -ferror-limit 1 -Werror |
| } |
| |
| usage() { |
| printf >&2 "Usage: [CLANG_FORMAT=clang-format] %s (gen|fmt|chk)\n" "$0" |
| |
| return 1 |
| } |
| |
| _main() { |
| local cmd |
| cmd=${1:-} |
| local TOPLEVEL |
| TOPLEVEL=$(git rev-parse --show-toplevel) |
| cd "${TOPLEVEL}" |
| case "${cmd}" in |
| gen) |
| gen |
| ;; |
| fmt) |
| fmt |
| ;; |
| chk) |
| chk |
| ;; |
| *) |
| usage |
| ;; |
| esac |
| } |
| |
| _main "$@" |