| #!/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 "$@" |