Skip to content
This repository was archived by the owner on Dec 25, 2022. It is now read-only.

Commit db3b753

Browse files
committed
Meta: Add minimalistic formatting/style checks
This patch adds a modified copy of the Serenity repo style checking scripts.
1 parent addabea commit db3b753

File tree

5 files changed

+304
-0
lines changed

5 files changed

+304
-0
lines changed

Meta/check-newlines-at-eof.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import re
5+
import subprocess
6+
import sys
7+
8+
9+
RE_RELEVANT_FILE_EXTENSION = re.compile('\\.(cpp|h|gml|html|js|css|sh|py|json|txt)$')
10+
11+
12+
def should_check_file(filename):
13+
if not RE_RELEVANT_FILE_EXTENSION.search(filename):
14+
return False
15+
if filename.endswith('.txt'):
16+
return 'CMake' in filename
17+
return True
18+
19+
20+
def find_files_here_or_argv():
21+
if len(sys.argv) > 1:
22+
raw_list = sys.argv[1:]
23+
else:
24+
process = subprocess.run(["git", "ls-files"], check=True, capture_output=True)
25+
raw_list = process.stdout.decode().strip('\n').split('\n')
26+
27+
return filter(should_check_file, raw_list)
28+
29+
30+
def run():
31+
"""Check files checked in to git for trailing newlines at end of file."""
32+
no_newline_at_eof_errors = []
33+
blank_lines_at_eof_errors = []
34+
35+
did_fail = False
36+
for filename in find_files_here_or_argv():
37+
with open(filename, "r") as f:
38+
f.seek(0, os.SEEK_END)
39+
40+
f.seek(f.tell() - 1, os.SEEK_SET)
41+
if f.read(1) != '\n':
42+
did_fail = True
43+
no_newline_at_eof_errors.append(filename)
44+
continue
45+
46+
while True:
47+
f.seek(f.tell() - 2, os.SEEK_SET)
48+
char = f.read(1)
49+
if not char.isspace():
50+
break
51+
if char == '\n':
52+
did_fail = True
53+
blank_lines_at_eof_errors.append(filename)
54+
break
55+
56+
if no_newline_at_eof_errors:
57+
print("Files with no newline at the end:", " ".join(no_newline_at_eof_errors))
58+
if blank_lines_at_eof_errors:
59+
print("Files that have blank lines at the end:", " ".join(blank_lines_at_eof_errors))
60+
61+
if did_fail:
62+
sys.exit(1)
63+
64+
65+
if __name__ == '__main__':
66+
os.chdir(os.path.dirname(__file__) + "/..")
67+
run()

Meta/check-style.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import re
5+
import subprocess
6+
import sys
7+
8+
# Ensure copyright headers match this format and are followed by a blank line:
9+
# /*
10+
# * Copyright (c) YYYY(-YYYY), Whatever
11+
# * ... more of these ...
12+
# *
13+
# * SPDX-License-Identifier: BSD-2-Clause
14+
# */
15+
GOOD_LICENSE_HEADER_PATTERN = re.compile(
16+
'^/\\*\n' +
17+
'( \\* Copyright \\(c\\) [0-9]{4}(-[0-9]{4})?, .*\n)+' +
18+
' \\*\n' +
19+
' \\* SPDX-License-Identifier: BSD-2-Clause\n' +
20+
' \\*/\n' +
21+
'\n')
22+
LICENSE_HEADER_CHECK_EXCLUDES = {}
23+
24+
# We check that "#pragma once" is present
25+
PRAGMA_ONCE_STRING = '#pragma once'
26+
PRAGMA_ONCE_CHECK_EXCLUDES = {}
27+
28+
# We make sure that there's a blank line before and after pragma once
29+
GOOD_PRAGMA_ONCE_PATTERN = re.compile('(^|\\S\n\n)#pragma once(\n\n\\S.|$)')
30+
31+
32+
def should_check_file(filename):
33+
if not filename.endswith('.cpp') and not filename.endswith('.h'):
34+
return False
35+
return True
36+
37+
38+
def find_files_here_or_argv():
39+
if len(sys.argv) > 1:
40+
raw_list = sys.argv[1:]
41+
else:
42+
process = subprocess.run(["git", "ls-files"], check=True, capture_output=True)
43+
raw_list = process.stdout.decode().strip('\n').split('\n')
44+
45+
return filter(should_check_file, raw_list)
46+
47+
48+
def run():
49+
errors_license = []
50+
errors_pragma_once_bad = []
51+
errors_pragma_once_missing = []
52+
53+
for filename in find_files_here_or_argv():
54+
with open(filename, "r") as f:
55+
file_content = f.read()
56+
if not any(filename.startswith(forbidden_prefix) for forbidden_prefix in LICENSE_HEADER_CHECK_EXCLUDES):
57+
if not GOOD_LICENSE_HEADER_PATTERN.search(file_content):
58+
errors_license.append(filename)
59+
if filename.endswith('.h'):
60+
if any(filename.startswith(forbidden_prefix) for forbidden_prefix in PRAGMA_ONCE_CHECK_EXCLUDES):
61+
# File was excluded
62+
pass
63+
elif GOOD_PRAGMA_ONCE_PATTERN.search(file_content):
64+
# Excellent, the formatting is correct.
65+
pass
66+
elif PRAGMA_ONCE_STRING in file_content:
67+
# Bad, the '#pragma once' is present but it's formatted wrong.
68+
errors_pragma_once_bad.append(filename)
69+
else:
70+
# Bad, the '#pragma once' is missing completely.
71+
errors_pragma_once_missing.append(filename)
72+
73+
if errors_license:
74+
print("Files with bad licenses:", " ".join(errors_license))
75+
if errors_pragma_once_missing:
76+
print("Files without #pragma once:", " ".join(errors_pragma_once_missing))
77+
if errors_pragma_once_bad:
78+
print("Files with a bad #pragma once:", " ".join(errors_pragma_once_bad))
79+
80+
if errors_license or errors_pragma_once_missing or errors_pragma_once_bad:
81+
sys.exit(1)
82+
83+
84+
if __name__ == '__main__':
85+
os.chdir(os.path.dirname(__file__) + "/..")
86+
run()

Meta/lint-ci.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
6+
cd "${script_path}/.." || exit 1
7+
8+
RED='\033[0;31m'
9+
GREEN='\033[0;32m'
10+
NC='\033[0m' # No Color
11+
12+
FAILURES=0
13+
14+
set +e
15+
16+
for cmd in \
17+
Meta/check-newlines-at-eof.py \
18+
Meta/check-style.py; do
19+
echo "Running ${cmd}"
20+
if time "${cmd}" "$@"; then
21+
echo -e "[${GREEN}OK${NC}]: ${cmd}"
22+
else
23+
echo -e "[${RED}FAIL${NC}]: ${cmd}"
24+
((FAILURES+=1))
25+
fi
26+
done
27+
28+
echo "Running Meta/lint-clang-format.sh"
29+
if time Meta/lint-clang-format.sh --overwrite-inplace "$@" && git diff --exit-code; then
30+
echo -e "[${GREEN}OK${NC}]: Meta/lint-clang-format.sh"
31+
else
32+
echo -e "[${RED}FAIL${NC}]: Meta/lint-clang-format.sh"
33+
((FAILURES+=1))
34+
fi
35+
36+
exit "${FAILURES}"

Meta/lint-clang-format.sh

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
6+
cd "${script_path}/.." || exit 1
7+
8+
if [ "$#" -eq "1" ]; then
9+
mapfile -t files < <(
10+
git ls-files -- \
11+
'*.cpp' \
12+
'*.h'
13+
)
14+
else
15+
files=()
16+
for file in "${@:2}"; do
17+
if [[ "${file}" == *".cpp" || "${file}" == *".h" ]]; then
18+
files+=("${file}")
19+
fi
20+
done
21+
fi
22+
23+
if (( ${#files[@]} )); then
24+
CLANG_FORMAT=false
25+
if command -v clang-format-14 >/dev/null 2>&1 ; then
26+
CLANG_FORMAT=clang-format-14
27+
elif command -v clang-format >/dev/null 2>&1 ; then
28+
CLANG_FORMAT=clang-format
29+
if ! "${CLANG_FORMAT}" --version | awk '{ if (substr($NF, 1, index($NF, ".") - 1) < 14) exit 1; }'; then
30+
echo "You are using '$("${CLANG_FORMAT}" --version)', which appears to not be clang-format 14 or later."
31+
echo "It is very likely that the resulting changes are not what you wanted."
32+
fi
33+
else
34+
echo "clang-format-14 is not available, but C or C++ files need linting! Either skip this script, or install clang-format-14."
35+
echo "(If you install a package 'clang-format', please make sure it's version 14 or later.)"
36+
exit 1
37+
fi
38+
39+
if [ "$#" -gt "0" ] && [ "--overwrite-inplace" = "$1" ] ; then
40+
true # The only way to run this script.
41+
else
42+
# Note that this branch also covers --help, -h, -help, -?, etc.
43+
echo "USAGE: $0 --overwrite-inplace"
44+
echo "The argument is necessary to make you aware that this *will* overwrite your local files."
45+
exit 1
46+
fi
47+
48+
echo "Using ${CLANG_FORMAT}"
49+
50+
"${CLANG_FORMAT}" -style=file -i "${files[@]}"
51+
echo "Maybe some files have changed. Sorry, but clang-format doesn't indicate what happened."
52+
else
53+
echo "No .cpp or .h files to check."
54+
fi

Meta/lint-commit.sh

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env bash
2+
3+
# the file containing the commit message is passed as the first argument
4+
commit_file="$1"
5+
commit_message=$(cat "$commit_file")
6+
7+
error() {
8+
echo -e "\033[0;31m$1:\033[0m"
9+
echo "$commit_message"
10+
exit 1
11+
}
12+
13+
# fail if the commit message contains windows style line breaks (carriage returns)
14+
if grep -q -U $'\x0D' "$commit_file"; then
15+
error "Commit message contains CRLF line breaks (only unix-style LF linebreaks are allowed)"
16+
fi
17+
18+
line_number=0
19+
while read -r line; do
20+
# break on git cut line, used by git commit --verbose
21+
if [[ "$line" == "# ------------------------ >8 ------------------------" ]]; then
22+
break
23+
fi
24+
25+
# ignore comment lines
26+
[[ "$line" =~ ^#.* ]] && continue
27+
# ignore overlong 'fixup!' commit descriptions
28+
[[ "$line" =~ ^fixup!\ .* ]] && continue
29+
30+
((line_number += 1))
31+
line_length=${#line}
32+
33+
if [[ $line_number -eq 2 ]] && [[ $line_length -ne 0 ]]; then
34+
error "Empty line between commit title and body is missing"
35+
fi
36+
37+
category_pattern='^(Revert "|\S+: )'
38+
if [[ $line_number -eq 1 ]] && (echo "$line" | grep -E -v -q "$category_pattern"); then
39+
error "Missing category in commit title (if this is a fix up of a previous commit, it should be squashed)"
40+
fi
41+
42+
title_case_pattern="^\S.*?: [A-Z0-9]"
43+
if [[ $line_number -eq 1 ]] && (echo "$line" | grep -E -v -q "$title_case_pattern"); then
44+
error "First word of commit after the subsystem is not capitalized"
45+
fi
46+
47+
if [[ $line_number -eq 1 ]] && [[ "$line" =~ \.$ ]]; then
48+
error "Commit title ends in a period"
49+
fi
50+
51+
url_pattern="([a-z]+:\/\/)?(([a-zA-Z0-9_]|-)+\.)+[a-z]{2,}(:\d+)?([a-zA-Z_0-9@:%\+.~\?&\/=]|-)+"
52+
if [[ $line_length -gt 72 ]] && (echo "$line" | grep -E -v -q "$url_pattern"); then
53+
error "Commit message lines are too long (maximum allowed is 72 characters)"
54+
fi
55+
56+
if [[ "$line" == "Signed-off-by: "* ]]; then
57+
error "Commit body contains a Signed-off-by tag"
58+
fi
59+
60+
done <"$commit_file"
61+
exit 0

0 commit comments

Comments
 (0)