Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clang-format entire codebase #450

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions lint.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
@echo off
setlocal enabledelayedexpansion

rem Runs clang-format on all *.cpp/*.h/*.json files in the project, excluding builds/
set "FILE_TYPES=*.cpp *.h *.json"
set "EXCLUDED=builds"

rem Make sure we have a clang-format to use.
rem Prefer any clang-format already in the user's %PATH%.
set "PATH=%PATH%;%VCINSTALLDIR%\Tools\Llvm\bin\"
where /q clang-format
if %ERRORLEVEL% neq 0 (
echo Unable to find clang-format. Are you in a Developer command prompt?
exit /b 1
)

rem Figure out how parallel we're gonna be
if /i "%1" == "-j" (
shift
set /a JOBS=%1
) else if "%1" == "" (
set /a JOBS=%NUMBER_OF_PROCESSORS%
) else (
echo Usage: lint.bat ^[-j ^<NUM_JOBS^>^]
echo If -j is not specified, NUM_JOBS defaults to the number of processors ^(%NUMBER_OF_PROCESSORS%^)
exit /b 1
)

rem Generate a temporary filename to store the list of files
:gen_temp_file
set CPP_FILES="%TMP%\lint~%RANDOM%.tmp"
if exist %CPP_FILES% goto :gen_temp_file

rem Find all the files, and split them up amongs %JOBS% different files, round-robin style
set /a i=1
for /f "usebackq tokens=*" %%A in (`dir %FILE_TYPES% /s /b ^| findstr /v "%EXCLUDED%"`) do (
rem !i! syntax here is "immediate" expansion: https://ss64.com/nt/delayedexpansion.html
echo %%A >> %CPP_FILES%-!i!
set /a i=!i! + 1
if !i! gtr %JOBS% (set /a i=1)
)

rem start a clang-format task for each filelist created
for /l %%A in (1,1,%JOBS%) do (
rem Use `start /b` to asynchronously spawn a new cmd.exe session running a clang-format and then a delete
rem The clang-format cmd is stdout/stderr redirected to NUL, and the ^& is an "and then" joiner
rem In batch, `foo & bar` is a way to indicate both foo and bar on one line, one after another. The ^ here
rem is an escape, indicating that the & character should be passed to cmd, *not* start
start "" /b cmd /c clang-format -i --files %CPP_FILES%-%%A >NUL 2>&1 ^& del %CPP_FILES%-%%A
)

rem Loop until all split filelists are deleted by their asynchronous cmds. Poor man's semaphore, file-style.
:wait_for_done
for /l %%A in (1,1,%JOBS%) do (
if exist %CPP_FILES%-%%A goto :wait_for_done
)
74 changes: 74 additions & 0 deletions lint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/bin/sh

# Runs clang-format on all *.cpp/*.h/*.json files in the project, excluding builds/
FILE_TYPES="*.cpp *.h *.json"
EXCLUDED="*/builds/*"

# Make sure we have a clang-format to use.
# Prefer any clang-format already in the user's $PATH.
# PATH=$PATH:/usr/bin/
which -s clang-format || (
echo Unable to find clang-format in \$PATH.
exit 1
)

# parse arguments
while [ "$1" != "" ]; do
case $1 in
-j | --jobs )
shift
JOBS="$1"
;;
* )
echo "Usage: lint.sh [-j|--jobs <NUM_JOBS>]"
echo " If -j is not specified, NUM_JOBS defaults to the number of CPU threads."
exit 1
;;
esac
shift
done

# Figure out how parallel we're gonna be
# default to simple single-threaded xargs
EXECUTOR=xargs
if [ "$JOBS" != "1" ]; then
# if xargs supports parallelism, use that
if (echo foo bar | xargs -lkj -P 0$JOBS true 2>/dev/null); then
# prefix the $JOBS with 0 so that unspecified JOBS becomes "0" and specified becomes "02" which is still valid
# -n 1 so that xargs doesn't simply collect all the args into one job and break parallelism regardless
EXECUTOR="xargs -P 0$JOBS -n 1"
# if xargs doesn't support it, see if we can use GNU parallel
elif which -s parallel; then
# -X to spread the parameters evenly among jobs
EXECUTOR="parallel -X"
# if JOBS is explicitly set, add it (don't use 0-prefix trick; it triggers some buggy behavior in the "-j 0" case)
if [ "$JOBS" != "" ]; then
EXECUTOR="$EXECUTOR -j $JOBS"
fi
# if nothing supports parallelism, warn if the user appears to expect it
elif [ "$JOBS" != "" ]; then
echo "Warning: Parallel jobs specified, but installed xargs does not support -P and GNU parallel not found. Defaulting to single-threaded." >&2
fi
fi

# takes the FILE_TYPES and EXCLUDED vars and concats them into find parameters
function path_args() {
for i in $1; do
echo -path "$i" -or
done
}

# finally, run the job
find . \
-type f \
\( \
$(path_args "$FILE_TYPES") \
-false \
\) \
-not \( \
$(path_args "$EXCLUDED") \
-false \
\) \
-print0 |
# pipe the file list into the executor (xargs or parallel) to run clang-format
$EXECUTOR --null clang-format -i