From 269501b526e0f1c10a42758ed80bbd528e21f571 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Thu, 14 Jun 2018 15:02:39 -0500 Subject: [PATCH] contrib/utilities/indent: Reorganize script This commit - reorganizes the core indenting logic into a indent_common.sh file - cleans up find and indenting logic to make everything more readable - prepares for more specialized indent versions (see #6673) --- contrib/utilities/indent | 116 +++---------------- contrib/utilities/indent_common.sh | 173 +++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+), 103 deletions(-) create mode 100644 contrib/utilities/indent_common.sh diff --git a/contrib/utilities/indent b/contrib/utilities/indent index fdd3e38c57..a33e7be7e6 100755 --- a/contrib/utilities/indent +++ b/contrib/utilities/indent @@ -23,129 +23,39 @@ # While we're already touching every file, this script also makes # sure we set permissions correctly # -# The script needs to be executed as +# The script needs to be executed as # ./contrib/utilities/indent # from the top-level directory of the source tree, or via # make indent # from a build directory. # -if test ! -d source -o ! -d include -o ! -d examples ; then +if [ ! -f contrib/utilities/indent_common.sh ]; then echo "*** This script must be run from the top-level directory of deal.II." exit 1 fi -# Add the location 'download_clang_format' or 'compile_clang_format' -# installs clang-format to to the local PATH. -CLANG_FORMAT_PATH="$(cd "$(dirname "$0")" && pwd)/programs/clang-6/bin" -export PATH="${CLANG_FORMAT_PATH}:${PATH}" - -if ! [ -x "$(command -v clang-format)" ]; then - echo "*** No clang-format program found." - echo "***" - echo "*** You can run the 'download_clang_format' script or the" - echo "*** 'compile_clang_format' script for obtaining a compatible" - echo "*** binary and installing to an appropriate directory." - exit 1 -fi - -# Make sure to have the right version. We know that clang-6.0.0 -# and clang-6.0.1 work. Hence, test for clang-6.0. -CLANG_FORMAT_VERSION="$(clang-format --version)" -CLANG_FORMAT_MAJOR_VERSION=$(echo "${CLANG_FORMAT_VERSION}" | sed 's/^[^0-9]*\([0-9]*\).*$/\1/g') -CLANG_FORMAT_MINOR_VERSION=$(echo "${CLANG_FORMAT_VERSION}" | sed 's/^[^0-9]*[0-9]*\.\([0-9]*\).*$/\1/g') - -if [ "${CLANG_FORMAT_MAJOR_VERSION}" -ne 6 ] || [ "${CLANG_FORMAT_MINOR_VERSION}" -ne 0 ]; then - echo "*** Found a version of clang-format different than the required version 6.0." - exit 1 -fi +source contrib/utilities/indent_common.sh # -# Collect all header and source files and process them in batches of 50 -# files with up to 10 in parallel -# -# The command line is a bit complicated, so let's discuss the more -# complicated arguments: -# - For 'find', -print0 makes sure that file names are separated by \0 -# characters, as opposed to the default \n. That's because, surprisingly, -# \n is a valid character in a file name, whereas \0 is not -- so it -# serves as a good candidate to separate individual file names. -# - For 'xargs', -0 does the opposite: it separates filenames that are -# delimited by \0 -# - -n 50 calls the following script with up to 50 file names at a time -# - -P 10 calls the following script up to 10 times in parallel -# -find tests include source examples \ - \( -name '*.cc' -o -name '*.h' -o -name '*.cu' -o -name '*.cuh' \) -print0 | - xargs -0 -n 50 -P 10 clang-format -i - -# -# Use the same process to set file permissions for all source files. +# Run sanity checks: # -find tests include source examples \ - \( -name '*.cc' -o -name '*.h' -o -name '*.cu' -o -name '*.cuh' \) -print0 | - xargs -0 -n 50 -P 10 chmod 644 +checks # -# Convert DOS formatted files to unix file format by stripping out -# carriage returns (15=0x0D): +# Process all source and header files: # -dos_to_unix() -{ - f=$1 - tr -d '\015' <"$f" >"$f.tmp" - diff -q "$f" "$f.tmp" >/dev/null || mv "$f.tmp" "$f" - rm -f "$f.tmp" -} -export -f dos_to_unix - -find tests include source examples \ - \( -name '*.cc' -o -name '*.h' -o -name '*.cu' -o -name '*.cuh' \) -print0 | - xargs -0 -n 1 -P 10 -I {} bash -c 'dos_to_unix "$@"' _ {} +process "tests include source examples" ".*\.(cc|h|cu|cuh)" format_file +process "source" ".*\.inst.in" format_inst # -# Format .inst.in files. We need to replace \{ and \} by a sentinel because -# clang-format happily strips away the backslash. Further, there is a minor -# caveat: clang-format automatically renames a comment after a closing -# bracket for a namespace to "} // namespace FooBar". Thus use "namespace" -# as keyword: +# Fix permissions and convert to unix line ending if necessary: # -format_inst() -{ - f=$1 - cp "$f" "$f.tmp" - sed -i.orig 's#\\{#{ // namespace#g' "$f.tmp" - sed -i.orig 's#\\}#} // namespace#g' "$f.tmp" - clang-format -i "$f.tmp" - sed -i.orig 's#{ // namespace#\\{#g' "$f.tmp" - sed -i.orig 's#}[ ]*// namespace.*#\\}#g' "$f.tmp" - if ! diff -q "$f" "$f.tmp" >/dev/null - then - cp "$f.tmp" "$f" - fi - rm "$f.tmp" "$f.tmp.orig" -} -export -f format_inst +process "tests include source examples" \ + ".*\.(cc|h|cu|cuh|inst.in|output.*|cmake)" fix_permissions -# -# Now do the formatting. The arguments are as discussed above, plus the -# following: -# - '-n 1' implies that the following script is called for each file -# individually -# - '-I {}' tells 'xargs' to substitute '{}' in the following by the -# one file name we process at a time -# - 'bash -c' executes the command that follows. Here, this is -# 'format_inst "$@"' where 'format_inst' is the macro exported -# above, and '$@' expands to the list of arguments passed on the -# command line, starting at $1. Because we execute a command with -# -c, there is no $0 for this bash invokation, and if we just had -# {} following the argument of -c, then the first element of that -# list would be ignored. To avoid this, we need a dummy argument -# to take the role of $0 so that {} can be expanded into $1. We -# simply use '_' here, but any other string would do fine as well. -# -find source -name '*.inst.in' -print0 | - xargs -0 -n 1 -P 10 -I {} bash -c 'format_inst "$@"' _ {} +process "tests include source examples" \ + ".*\.(cc|h|cu|cuh|inst.in|output.*|cmake)" dos_to_unix diff --git a/contrib/utilities/indent_common.sh b/contrib/utilities/indent_common.sh new file mode 100644 index 0000000000..48450ff697 --- /dev/null +++ b/contrib/utilities/indent_common.sh @@ -0,0 +1,173 @@ +#!/bin/bash +## --------------------------------------------------------------------- +## +## Copyright (C) 2018 by the deal.II authors +## +## This file is part of the deal.II library. +## +## The deal.II library is free software; you can use it, redistribute +## it, and/or modify it under the terms of the GNU Lesser General +## Public License as published by the Free Software Foundation; either +## version 2.1 of the License, or (at your option) any later version. +## The full text of the license can be found in the file LICENSE at +## the top level of the deal.II distribution. +## +## --------------------------------------------------------------------- + +# +# This file contains a number of common functions used all indent scripts +# + +# +# This function checks that we are in the root directory and that +# clang-format is available. It is called by both indent and indent-branch +# to ensure that the rest of the indentation pipeline makes sense. +# + +checks() { + if test ! -d source -o ! -d include -o ! -d examples ; then + echo "*** This script must be run from the top-level directory of deal.II." + exit 1 + fi + + # Add the location 'download_clang_format' or 'compile_clang_format' + # installs clang-format to to the local PATH. + CLANG_FORMAT_PATH="$(cd "$(dirname "$0")" && pwd)/programs/clang-6/bin" + export PATH="${CLANG_FORMAT_PATH}:${PATH}" + + if ! [ -x "$(command -v clang-format)" ]; then + echo "*** No clang-format program found." + echo "***" + echo "*** You can run the 'download_clang_format' script or the" + echo "*** 'compile_clang_format' script for obtaining a compatible" + echo "*** binary and installing to an appropriate directory." + exit 1 + fi + + # Make sure to have the right version. We know that clang-6.0.0 + # and clang-6.0.1 work. Hence, test for clang-6.0. + CLANG_FORMAT_VERSION="$(clang-format --version)" + CLANG_FORMAT_MAJOR_VERSION=$(echo "${CLANG_FORMAT_VERSION}" | sed 's/^[^0-9]*\([0-9]*\).*$/\1/g') + CLANG_FORMAT_MINOR_VERSION=$(echo "${CLANG_FORMAT_VERSION}" | sed 's/^[^0-9]*[0-9]*\.\([0-9]*\).*$/\1/g') + + if [ "${CLANG_FORMAT_MAJOR_VERSION}" -ne 6 ] || [ "${CLANG_FORMAT_MINOR_VERSION}" -ne 0 ]; then + echo "*** Found a version of clang-format different than the required version 6.0." + exit 1 + fi +} + +# +# Mac OSX's mktemp doesn't know the --tmpdir option without argument. So, +# let's do all of that by hand: +# +export TMPDIR="${TMPDIR:-/tmp}" + +# +# In order to format .cc and .h files we have to make sure that we override +# the source/header file only if the actual contents changed. +# Unfortunately, clang-format isn't exactly helpful there. Thus, use a +# temporary file and diff as a workaround. +# + +format_file() +{ + file="${1}" + tmpfile="$(mktemp "${TMPDIR}/$(basename "$1").tmp.XXXXXXXX")" + + clang-format "${file}" > "${tmpfile}" + diff -q "${file}" "${tmpfile}" >/dev/null || mv "${tmpfile}" "${file}" + rm -f "${tmpfile}" +} +export -f format_file + +# +# In order to format .inst.in files, we need to replace \{ and \} by a +# sentinel because clang-format happily strips away the backslash. Further, +# there is a minor caveat: clang-format automatically renames a comment +# after a closing bracket for a namespace to "} // namespace FooBar". Thus +# use "namespace" as keyword: +# + +format_inst() +{ + file="${1}" + tmpfile="$(mktemp "${TMPDIR}/$(basename "$1").tmp.XXXXXXXX")" + + cp "${file}" "${tmpfile}" + sed -i -e 's#\\{#{ // namespace#g' -e 's#\\}#} // namespace#g' "${tmpfile}" + + # + # Yes, we have to call clang-format in this weird way to ensure that it + # picks up and uses the .clang-format style-sheet in the current + # directory. + # + clang-format < "${tmpfile}" > "${tmpfile}new" + + sed -i -e 's#{ // namespace#\\{#g' -e 's#}[ ]*// namespace.*#\\}#g' \ + "${tmpfile}new" + + diff -q "${file}" "${tmpfile}new" >/dev/null || mv "${tmpfile}new" "${file}" + rm -f "${tmpfile}" "${tmpfile}new" +} +export -f format_inst + +# +# Convert DOS formatted files to unix file format by stripping out +# carriage returns (15=0x0D): +# + +dos_to_unix() +{ + file="${1}" + tmpfile="$(mktemp "${TMPDIR}/$(basename "$1").tmp.XXXXXXXX")" + + tr -d '\015' <"${file}" >"${tmpfile}" + diff -q "${file}" "${tmpfile}" >/dev/null || mv "${tmpfile}" "${file}" + rm -f "${tmpfile}" +} +export -f dos_to_unix + +# +# Fix permissions +# + +fix_permissions() +{ + file="${1}" + + chmod 644 "${file}" +} +export -f fix_permissions + +# +# Collect all files found in a list of directories "${1}$" matching a +# regular expression "${2}$", and process them with a command "${3}" on 10 +# threads in parallel. +# +# The command line is a bit complicated, so let's discuss the more +# complicated arguments: +# - For 'find', -print0 makes sure that file names are separated by \0 +# characters, as opposed to the default \n. That's because, surprisingly, +# \n is a valid character in a file name, whereas \0 is not -- so it +# serves as a good candidate to separate individual file names. +# - For 'xargs', -0 does the opposite: it separates filenames that are +# delimited by \0 +# - the options "-n 1 -P 10" make sure that the following script with be +# called exactly with one file name as argument at a time, but we allow +# execution for up to 10 times in parallel +# + +process() +{ + case "${OSTYPE}" in + darwin*) + find -E ${1} -regex "${2}" -print0 | + xargs -0 -n 1 -P 10 -I {} bash -c "${3} {}" + ;; + *) + find ${1} -regextype egrep -regex "${2}" -print0 | + xargs -0 -n 1 -P 10 -I {} bash -c "${3} {}" + ;; + esac +} + -- 2.39.5